
Принимает HTML от третьих сторон и создаёт HTML, безопасный для встраивания в ваше веб-приложение. Быстро и легко настраивается.
Быстрый и легко настраиваемый HTML-санитайзер, написанный на Java, который позволяет включать в ваше веб-приложение HTML, созданный третьими лицами, защищая при этом от XSS.
Существующая зависимость — от 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);
Примечание: Если строка очищается без уведомлений об изменениях, это не означает, что входная строка обязательно безопасна для использования. Используйте только выходные данные санитайзера.
Санитайзер гарантирует, что выходные данные находятся в подмножестве HTML, о значении которого общепринятые анализаторы HTML договорятся, но отсутствие уведомлений не означает, что входные данные находятся в таком подмножестве, а лишь то, что они не содержат элементов или атрибутов, которые были удалены.
См. раздел "Зачем очищать, если можно проверить" для получения дополнительной информации по этой теме.
Если вы хотите сообщить об уязвимости, пожалуйста, ознакомьтесь с правилами аудиторской проверки (англ.).
Подпишитесь на список рассылки, чтобы быть в курсе известных уязвимостей и важных обновлений.
Если вы хотите внести свой вклад, напишите @mvsamuel или @manicode.
Мы приветствуем сообщения о проблемах и PR. PR, которые изменяют поведение или добавляют функциональность, должны включать как позитивные, так и негативные тесты.
Пожалуйста, имейте в виду, что вклад подпадает под действие лицензии Apache 2.0.