
java-html-sanitizer v20260921.1
타사 HTML을 입력받아 웹 애플리케이션에 안전하게 포함할 수 있는 HTML을 생성합니다. 빠르고 설정하기 쉽습니다.
OWASP Java HTML Sanitizer
Java로 작성된 빠르고 구성하기 쉬운 HTML Sanitizer로, 웹 애플리케이션에서 제3자가 작성한 HTML을 포함시키면서 XSS로부터 보호할 수 있게 해줍니다.
이 sanitizer JAR은 런타임 의존성이 없습니다. 유일한 컴파일 타임
의존성은 spotbugs-annotations(provided 스코프, 어노테이션 전용)이며,
다른 jar들은 테스트 스위트에서만 필요합니다.
이 코드는 보안 모범 사례를 염두에 두고 작성되었으며, 방대한 테스트 스위트를 갖추고 있고, 적대적 보안 검토를 거쳤습니다.
목차
시작하기
시작하기에는 Maven 사용 여부에 관계없이 시작하는 방법에 대한 지침이 포함되어 있습니다.
저장소 구조
빌드에는 JDK 11 이상이 필요합니다. 저장소 루트에서 다음 명령으로 모든 Maven 모듈을 빌드하고 테스트를 실행합니다:
./mvnw clean verify
Maven wrapper는 필요한 Maven 버전을 고정합니다. -pl로 모듈을 선택하는 경우, Maven이 의존하는 모듈을 빌드하도록 -am도 함께 사용하세요.
- owasp-java-html-sanitizer/에는 게시된 라이브러리, 해당 테스트, 그리고 Java 모듈 디스크립터가 포함되어 있습니다.
- java8-shim/과 java10-shim/은 라이브러리 JAR에 번들로 포함되는 호환성 코드를 구현합니다.
- examples/에는 읽고 복사할 수 있는 샘플 정책이 포함되어 있으며, 테스트되지만 게시되지는 않습니다.
- empiricism/에는 sanitizer의 HTML 요소 테이블을 생성하는 데 사용된 브라우저 실험이 포함되어 있습니다.
- docs/에는 사용자, 보안, 그리고 이력 문서가 포함되어 있습니다.
사전 패키징된 정책
다음 사전 패키징된 정책을 사용할 수 있습니다:
PolicyFactory policy = Sanitizers.FORMATTING.and(Sanitizers.LINKS);
String safeHTML = policy.sanitize(untrustedHTML);
정책 작성하기
tests 는 자신만의 정책을 구성하는 방법을 보여줍니다:
PolicyFactory policy = new HtmlPolicyBuilder()
.allowElements("a")
.allowUrlProtocols("https")
.allowAttributes("href").onElements("a")
.requireRelNofollowOnLinks()
.toFactory();
String safeHTML = policy.sanitize(untrustedHTML);
사용자 정의 정책
다음과 같은 작업을 수행하기 위해
사용자 정의 정책을
작성할 수 있습니다. 예를 들어 h1을 특정 클래스를 가진 div로 변경하는 등의 작업입니다:
PolicyFactory policy = new HtmlPolicyBuilder()
.allowElements("p")
.allowElements(
(String elementName, List<String> attrs) -> {
// Add a class attribute.
attrs.add("class");
attrs.add("header-" + elementName);
// Return elementName to include, null to drop.
return "div";
}, "h1", "h2", "h3", "h4", "h5", "h6")
.toFactory();
String safeHTML = policy.sanitize(untrustedHTML);
"a", "font", "img", "input", "span" 요소에 속성이 전혀 포함되지 않은 경우에도 필터를 통과하도록 허용하려면 allowWithoutAttributes() 메서드를 사용하여 해당 요소를 명시적으로 화이트리스트에 추가해야 합니다.
속성 정책을 사용하면 사용자 정의 코드도 실행할 수 있습니다. 속성 정책을 추가하더라도 style이나 URL 속성 검사와 같은 기본 정책이 약화되지는 않습니다.
PolicyFactory myPolicy = new HtmlPolicyBuilder()
.allowElements("div", "span")
.allowAttributes("data-foo")
.matching(
(String elementName, String attributeName, String value) -> {
// Return value for the attribute or null to drop.
return value;
})
.onElements("div", "span")
.toFactory();
전처리기
전처리기를 사용하면 텍스트를 삽입하고 대규모 구조 변경을 수행할 수 있습니다.
PolicyFactory myPolicy = new HtmlPolicyBuilder()
.withPreprocessor(
(HtmlStreamEventReceiver r) -> {
// Provide user with info about links before they click.
// Before: <a href="https://example.com/...">
// After: (https://example.com) <a href="https://example.com/...">
return new HtmlStreamEventReceiverWrapper(r) {
@Override public void openTag(String elementName, List<String> attrs) {
if ("a".equals(elementName)) {
for (int i = 0, n = attrs.size(); i < n; i += 2) {
if ("href".equals(attrs.get(i))) {
String url = attrs.get(i + 1);
String origin;
try {
URI uri = new URI(url);
String scheme = uri.getScheme();
String authority = uri.getRawAuthority();
if (scheme == null && authority == null) {
origin = null;
} else {
origin = (scheme != null ? scheme + ":" : "")
+ (authority != null ? "//" + authority : "");
}
} catch (URISyntaxException ex) {
origin = "about:invalid";
}
if (origin != null) {
text(" (" + origin + ") ");
}
}
}
}
super.openTag(elementName, attrs);
}
};
})
.allowElements("a")
.allowAttributes("href").onElements("a")
.allowStandardUrlProtocols()
...
.toFactory();
전처리는 정책이 적용되기 전에 수행되므로 출력의 보안에 영향을 줄 수 없습니다.
텔레메트리
정책이 요소나 속성을 거부하면 HtmlChangeListener에 알립니다.
이를 활용하여 정책 위반 추세를 추적하고 누군가가 보안을 침해하려고 시도하는 시점을 파악할 수 있습니다.
PolicyFactory myPolicyFactory = ...;
// If you need to associate reports with some context, you can do so.
MyContextClass myContext = ...;
String sanitizedHtml = myPolicyFactory.sanitize(
unsanitizedHtml,
new HtmlChangeListener<MyContextClass>() {
@Override
public void discardedTag(MyContextClass context, String elementName) {
// ...
}
@Override
public void discardedAttributes(
MyContextClass context, String elementName, String... attributeNames) {
// ...
}
},
myContext);
discardedAttributes는 남은 속성이 없어 제거된 요소에서 거부된 속성에 대해서도 발생합니다. 예를 들어 유일한 href가 거부된 링크의 경우입니다. 두 개의 기본 메서드는 이를 재정의하는 리스너를 위해 더 자세한 정보를 제공합니다. discardedAttribute는 거부된 각 속성의 값을 받고, discardedText는 정책이 유지된 리터럴 콘텐츠 요소에서 제거한 태그 유사 콘텐츠와 렌더러가 해당 요소에서 출력할 수 없었던 콘텐츠를 받습니다.
참고: 문자열이 변경 알림 없이 정제된다고 해서 입력 문자열이 반드시 안전하게 사용할 수 있는 것은 아닙니다. 정제기의 출력만 사용하십시오.
정제기는 출력이 일반적으로 사용되는 HTML 파서들이 의미에 대해 동의할 HTML의 하위 집합에 속하도록 보장하지만, 알림이 없다고 해서 입력이 그러한 하위 집합에 속한다는 것을 의미하지는 않으며, 단지 제거된 구조적 콘텐츠를 포함하지 않는다는 것만을 의미합니다.