
타사 HTML을 입력받아 웹 애플리케이션에 안전하게 포함할 수 있는 HTML을 생성합니다. 빠르고 설정하기 쉽습니다.
Java로 작성된 빠르고 구성하기 쉬운 HTML Sanitizer로, XSS를 방지하면서 제3자가 작성한 HTML을 웹 애플리케이션에 포함할 수 있게 해 줍니다.
기존 의존성은 JSR 305입니다. 다른 jar 파일들은 테스트 스위트에만 필요합니다. JSR 305 의존성은 컴파일 전용 의존성으로, 어노테이션에만 필요합니다.
이 코드는 보안 모범 사례를 염두에 두고 작성되었으며, 광범위한 테스트 스위트를 갖추고 있고 적대적 보안 검토를 거쳤습니다.
시작하기에는 Maven을 사용하거나 사용하지 않고 시작하는 방법에 대한 지침이 포함되어 있습니다.
사전 패키징된 정책을 사용할 수 있습니다:
PolicyFactory policy = Sanitizers.FORMATTING.and(Sanitizers.LINKS);
String safeHTML = policy.sanitize(untrustedHTML);
테스트는 자신만의 정책을 구성하는 방법을 보여 줍니다:
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 속성 검사와 같은 기본 정책이 약화되지는 않습니다.
new HtmlPolicyBuilder = new HtmlPolicyBuilder()
.allowElement("div", "span")
.allowAttributes("data-foo")
.matching(
(String elementName, String attributeName, String value) -> {
// Return value for the attribute or null to drop.
})
.onElements("div", "span")
.build()
전처리기를 사용하면 텍스트 삽입 및 대규모 구조 변경이 가능합니다.
new HtmlPolicyBuilder = new HtmlPolicyBuilder()
// Use a preprocessor to be backwards compatible with the
// <plaintext> element which
.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);
}
};
}
.allowElement("a")
...
.build()
전처리는 정책이 적용되기 전에 발생하므로 출력의 보안에는 영향을 줄 수 없습니다.
정책이 요소나 속성을 거부하면 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);
참고: 문자열이 변경 알림 없이 살균(sanitize)되었다고 해서 입력 문자열이 반드시 안전하다는 의미는 아닙니다. 살균기의 출력만 사용하세요.
살균기는 출력이 일반적으로 사용되는 HTML 파서들이 의미를 동일하게 해석하는 HTML의 하위 집합에 속하도록 보장하지만, 알림이 없다고 해서 입력이 그러한 하위 집합에 속한다는 의미는 아닙니다. 단지 제거된 요소나 속성이 포함되어 있지 않다는 뜻일 뿐입니다.
이 주제에 대한 자세한 내용은 "검증할 수 있는데 왜 살균하는가"를 참조하세요.
취약점을 신고하려면 AttackReviewGroundRules를 참조하세요.
메일링 리스트에 가입하여 알려진 취약점 및 중요한 업데이트에 대한 알림을 받으세요.
기여하고 싶다면 @mvsamuel 또는 @manicode에게 연락해 주세요.
이슈 보고 및 PR을 환영합니다. 동작을 변경하거나 기능을 추가하는 PR에는 긍정 테스트와 부정 테스트가 모두 포함되어야 합니다.
기여는 Apache 2.0 License에 해당함을 유의하세요.