
신뢰할 수 없는 HTML을 빠르고 구성 가능하게 정화하여 크로스 사이트 스크립팅(XSS) 공격을 방지하는 Java 라이브러리입니다. 정책 기반 스캐닝을 사용하여 사용자가 제공한 마크업을 삭제합니다.
신뢰할 수 없는 출처에서 오는 HTML을 빠르고 설정 가능하게 정리하는 라이브러리입니다. Java 7+를 지원합니다.
다른 방식으로 말하자면: 클라이언트가 프로필, 댓글 등에 제공하는 HTML에 악성 코드를 포함하지 않도록 하고, 이것이 서버에 저장되는 것을 방지하는 API입니다. 웹 애플리케이션에서 '악성 코드'라는 용어는 일반적으로 'JavaScript'를 의미합니다. 대부분의 경우, CSS(Cascading Stylesheets)는 JavaScript를 호출할 때만 악성으로 간주됩니다. 그러나 '정상적인' HTML과 CSS가 악의적인 방식으로 사용될 수 있는 많은 상황이 있습니다.
먼저 Maven에서 의존성을 추가합니다:
<dependency>
<groupId>org.owasp.antisamy</groupId>
<artifactId>antisamy</artifactId>
<version>LATEST_VERSION</version>
</dependency>
사이트의 AntiSamy 사용 사례는 대략 미리 정의된 정책 파일 중 하나와 비슷할 가능성이 높습니다. 각각은 사용자가 HTML(및 가능한 CSS) 서식 정보를 제공할 수 있도록 하는 '일반적인' 시나리오를 나타냅니다. 다양한 정책 파일을 살펴보겠습니다:
Slashdot은 사용자가 매우 제한된 HTML 마크업으로 뉴스 게시물에 익명으로 응답할 수 있는 기술 뉴스 사이트입니다. Slashdot은 가장 멋진 사이트 중 하나일 뿐만 아니라 여러 성공적인 공격을 받은 사이트이기도 합니다. Slashdot의 규칙은 상당히 엄격합니다: 사용자는 다음 HTML 태그만 제출할 수 있고 CSS는 허용되지 않습니다: <b>, <u>, <i>, <a>, <blockquote>.
따라서 우리는 상당히 유사한 기능을 허용하는 정책 파일을 만들었습니다. 글꼴, 색상 또는 강조에 직접 작용하는 모든 텍스트 서식 태그가 허용되었습니다.
eBay는 제가 알기로 우주에서 가장 인기 있는 온라인 경매 사이트입니다. 공개 사이트이므로 누구나 풍부한 HTML 콘텐츠로 목록을 게시할 수 있습니다. eBay가 표적으로서 매력적이기 때문에 몇 가지 복잡한 XSS 공격을 받은 것은 놀라운 일이 아닙니다. 목록은 Slashdot보다 훨씬 더 풍부한 콘텐츠를 포함할 수 있으므로 공격 표면이 상당히 더 큽니다.
MySpace는 이 프로젝트가 시작될 당시 가장 인기 있는 소셜 네트워킹 사이트였습니다. 사용자는 JavaScript를 포함하지 않는 한 원하는 거의 모든 HTML과 CSS를 제출할 수 있었습니다. MySpace는 사용자의 HTML을 검증하기 위해 단어 블랙리스트를 사용하고 있었고, 이것이 악명 높은 Samy 웜의 대상이 된 이유입니다. Samy 웜은 블랙리스트에 포함되어야 했던 단어(eval)와 결합된 조각 공격을 사용했으며, 이 프로젝트의 영감이 되었습니다.
이 정책 파일의 가능한 사용 사례는 잘 모르겠습니다. 모든 유효한 HTML 및 CSS 요소를 허용하려면(단, JavaScript나 명백한 CSS 관련 피싱 공격은 제외) 이 정책 파일을 사용할 수 있습니다. MySpace조차 이렇게 미친 적은 없었습니다. 그러나 모든 요소에 대한 기본 규칙을 포함하고 있기 때문에 좋은 참고 자료가 되며, 다른 정책 파일을 맞춤 설정할 때 지식 베이스로 사용할 수 있습니다.
AntiSamy 정책 파일에 대한 AntiSamy의 XML 스키마 정의(XSD) 개선 작업을 하던 중, AntiSamy가 실제로 XSD를 적용하지 않고 있다는 것을 발견했습니다. 따라서 AntiSamy 1.6.0부터 기본 동작을 변경하여 스키마를 적용하고, AntiSamy 정책이 유효하지 않으면 계속 진행하지 않도록 했습니다. 하지만 ...
개발자가 정책이 비준수인 경우 즉시 수정하지 못할 수도 있지만, 보안 개선, 기능 향상, 버그 수정을 위해 AntiSamy를 업그레이드하고 싶을 수 있다는 점을 인지하고 있습니다. 따라서 스키마 유효성 검사를 (임시로!) 비활성화하는 두 가지 방법을 제공했습니다:
Java 시스템 속성 설정: owasp.validator.validateschema를 false로 설정합니다. 이는 명령줄(예: -Dowasp.validator.validateschema=false) 또는 Java 시스템 속성 파일을 통해 수행할 수 있습니다. 둘 다 코드 변경이 필요하지 않습니다.
AntiSamy를 사용하는 코드를 변경하여 AntiSamy 정책을 로드하기 전에 Policy.setSchemaValidation(false)를 호출합니다. 이는 정적 호출이므로 한 번 비활성화되면 모든 새 Policy 인스턴스에 대해 비활성화됩니다.
AntiSamy 사용자가 XSD 준수 정책만 사용하도록 장려하기 위해 AntiSamy는 스키마 유효성 검사가 비활성화된 경우 항상 일종의 경고를 기록합니다. 정책이 비준수여서 수정할 수 있다는 WARN을 기록하거나, 정책이 준수되었지만 스키마 유효성 검사가 꺼져 있으므로 다시 켜야 한다는 WARN을 기록합니다(즉, 비활성화를 중지). 또한 AntiSamy 스키마가 로드되고 검증될 때 INFO 수준 로깅을 추가했습니다.
새로운 스키마 유효성 검사 기능을 비활성화하는 기능은 일시적으로, 적절히 유효한 AntiSamy 정책 파일로의 전환을 원활하게 하기 위한 것입니다. 다음 주요 릴리스에서 이 기능을 제거할 계획입니다. 이는 2022년 중후반경이 될 것으로 예상되므로, 곧바로 사라지지는 않을 것입니다. 이는 AntiSamy를 직접 사용하거나 ESAPI와 같은 다른 라이브러리를 통해 사용하는 개발 팀이 스키마 유효성 검사가 필수가 되기 전에 정책 파일을 스키마 준수하도록 만들 충분한 시간을 제공하기 위함입니다.
이 문제는 1.6.1에서 slf4j API만 사용하도록 신속히 수정되었습니다. 이제 AntiSamy는 로깅을 위해 slf4j-simple 라이브러리를 포함하지만, AntiSamy 사용자는 원하는 경우 대체 slf4j 호환 로깅 라이브러리를 가져와서 사용할 수 있습니다. 원한다면 slf4j-simple을 제외할 수도 있습니다.
경고: AntiSamy가 slf4j-simple을 구성 파일 없이 사용하면 메시지를 버퍼링 방식으로 표준 출력에 기록합니다. 따라서 PolicyException과 같은 예외가 발생하면 이러한 로그 메시지의 일부 또는 전체가 손실될 수 있습니다. 이는 slf4j-simple을 표준 오류에 기록하도록 구성하거나, 그렇게 하는 대체 slf4j 로거를 사용하여 해결할 수 있습니다.
기본 구성으로 AntiSamy를 배포하고 싶을 수도 있지만, 사이트에서 사용자가 허용할 수 있는 항목에 대해 엄격한 비즈니스 기반 규칙을 원할 가능성도 있습니다. 맞춤 설정을 결정하는 논의에서는 공격 표면도 고려해야 합니다. 이는 정책 파일에 비례하여 증가합니다.
AntiSamy 사용은 쉽습니다. 정책 파일로 AntiSamy를 호출하는 예제입니다:
import org.owasp.validator.html.*;
Policy policy = Policy.getInstance(POLICY_FILE_LOCATION);
AntiSamy as = new AntiSamy();
CleanResults cr = as.scan(dirtyInput, policy);
MyUserDAO.storeUserProfile(cr.getCleanHTML()); // some custom function
Policy 객체를 생성하는 몇 가지 방법이 있습니다. getInstance() 메서드는 다음 중 하나를 인수로 받을 수 있습니다:
String 파일 이름File 객체InputStream정책 파일은 다음 예제와 같이 AntiSamy#scan() 메서드에 두 번째 인수를 전달하여 파일 이름으로 참조할 수도 있습니다:
AntiSamy as = new AntiSamy();
CleanResults cr = as.scan(dirtyInput, policyFilePath);
마지막으로, 정책 파일은 두 번째 매개변수에 File 객체를 직접 참조할 수도 있습니다:
AntiSamy as = new AntiSamy();
CleanResults cr = as.scan(dirtyInput, new File(policyFilePath));
CleanResults 객체는 많은 유용한 정보를 제공합니다.
getErrorMessages() - String 오류 메시지 목록 -- 이 값이 0을 반환한다고 해서 공격이 없었다는 의미는 아닙니다!getCleanHTML() - 깨끗하고 안전한 HTML 출력getCleanXMLDocumentFragment() - getCleanHTML()에 반영된 깨끗하고 안전한 XMLDocumentFragmentgetScanTime() - 스캔 시간(초) 반환중요 참고: getErrorMessages() 메서드에 대해 많은 혼란이 있었습니다. getErrorMessages() 메서드는 빈 리스트를 반환한다고 해서 '이 입력이 안전한가?'라는 질문에 긍정적으로 대답하는 것이 아닙니다. 항상 정화된 입력을 사용해야 하며, 전달된 입력에 공격이 없었다고 확신할 수 있는 방법은 없습니다. 살균기의 효과에 중요한 직렬화 및 역직렬화 프로세스는 의도적으로 손실이 있으며 여러 공격 벡터를 통해 공격을 필터링합니다. 불행히도 이 전략의 절충점 중 하나는 나중에 공격이 있었는지 항상 알 수 없다는 것입니다. 따라서 getErrorMessages() API는 개발자가 공격이 있었는지 감지하는 데 도움이 되는 것이 아니라, 사용자가 자신의 의도가 좋은 입력이 시스템 요구 사항을 충족하도록 이해하는 데 도움을 주기 위해 존재합니다.
추가 문서는 이 Github 프로젝트의 위키 페이지(https://github.com/nahsra/antisamy/wiki)와 OWASP AntiSamy 프로젝트 페이지(https://owasp.org/www-project-antisamy/)에서 확인할 수 있습니다.
버그를 발견하셨다면 AntiSamy 저장소에 이슈를 생성해 주세요: https://github.com/nahsra/antisamy/issues
AntiSamy에서 취약점을 발견하셨다면 먼저 이슈 목록(위 참조)을 검색하여 이미 보고되었는지 확인해 주세요. 아직 보고되지 않았다면 Dave Wichers(dave.wichers at owasp.org)에게 직접 연락해 주십시오. 패치가 구현되고 배포되는 동안 사용자를 안전하게 보호하기 위해 GitHub 이슈를 통해 취약점을 보고하지 말아 주십시오. 취약점 발견에 대한 인정을 원하신다면 이 절차를 따라주십시오.
자세한 내용은 SECURITY.md 파일에서 확인할 수 있습니다.
소스에서 매우 쉽게 빌드하고 테스트할 수 있습니다:
$ git clone https://github.com/nahsra/antisamy
$ cd antisamy
$ mvn package
여기에 명시된 대로 BSD-3-Clause 라이선스에 따라 배포됩니다: LICENSE.