
java-html-sanitizer v20260921.1
获取第三方 HTML 并生成可安全嵌入到 Web 应用中的 HTML。快速且易于配置。
OWASP Java HTML Sanitizer
一个用 Java 编写、快速且易于配置的 HTML Sanitizer,让你可以在 Web 应用中包含第三方编写的 HTML,同时防御 XSS。
该 sanitizer JAR 没有运行时依赖。它唯一的编译时依赖是 spotbugs-annotations(provided 作用域,仅注解);其他 jar 仅测试套件需要。
此代码在编写时遵循安全最佳实践,拥有广泛的测试套件,并经过了对抗性安全审查。
目录
快速开始
快速开始 包含有关如何在使用或不使用 Maven 的情况下入门的说明。
仓库布局
构建需要 JDK 11 或更高版本。从仓库根目录,构建所有 Maven 模块并运行其测试,使用:
./mvnw clean verify
Maven wrapper 固定了所需的 Maven 版本。如果你使用 -pl 选择模块,请同时使用 -am,以便 Maven 构建它所依赖的模块。
- 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);
制定策略
PolicyFactory policy = new HtmlPolicyBuilder()
.allowElements("a")
.allowUrlProtocols("https")
.allowAttributes("href").onElements("a")
.requireRelNofollowOnLinks()
.toFactory();
String safeHTML = policy.sanitize(untrustedHTML);
自定义策略
你可以编写
自定义策略
来实现诸如将 h1 改为带有特定 class 的 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);
请注意,如果你希望这些元素在不包含任何属性的情况下也能通过过滤器,就需要使用 allowWithoutAttributes() 方法将 "a"、"font"、"img"、"input" 和 "span" 这些元素显式加入白名单。
属性策略 也允许运行自定义代码。添加属性策略不会削弱任何默认策略,例如 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 子集,但没有通知并不意味着输入属于这样的子集,只意味着它不包含被移除的结构性内容。
关于此主题的更多内容,请参阅 "Why sanitize when you can validate"。
有问题?
如果您希望报告漏洞,请参阅 安全策略 和 攻击审查基本规则。
订阅 邮件列表 或关注本仓库的 发布 和 安全公告 以获取已知 漏洞 和重要更新的通知。