Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
bluemonday — bluemonday: быстрый HTML-санитайзер на golang (вдохновлённый OWASP Java HTML Sanitizer) для очистки пользовательского контента от XSS | Kitploit
Инструменты/GitHubGitHub/microcosm-cc/bluemonday
Оборонительные ИнструментыСтатический анализАнализ уязвимостейАнализ КодаВеб-безопасностьБезопасность API
GitHubmicrocosm-cc/bluemonday

bluemonday

bluemonday: быстрый HTML-санитайзер на golang (вдохновлённый OWASP Java HTML Sanitizer) для очистки пользовательского контента от XSS

Репозиторий
3.7k19551 год назадПроверено Kitploit

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

bluemonday GoDoc Sourcegraph

bluemonday — это HTML-санитайзер, реализованный на Go. Он быстрый и легко настраивается.

bluemonday принимает недоверенный пользовательский контент в качестве входных данных и возвращает HTML, очищенный по белому списку разрешённых HTML-элементов и атрибутов, чтобы вы могли безопасно включать такой контент на свою веб-страницу.

Если вы принимаете пользовательский контент, а ваш сервер написан на Go, вам нужен bluemonday.

Политика по умолчанию для пользовательского контента (bluemonday.UGCPolicy().Sanitize()) превращает это:

root@kitploit:~
Hello <STYLE>.XSS{background-image:url("javascript:alert('XSS')");}</STYLE><A CLASS=XSS></A>World

в безвредное:

root@kitploit:~
Hello World

А это:

root@kitploit:~
<a href="javascript:alert('XSS1')" onmouseover="alert('XSS2')">XSS<a>

превращает в это:

root@kitploit:~
XSS

При этом продолжает разрешать вот это:

root@kitploit:~
<a href="http://www.google.com/">
  <img src="https://ssl.gstatic.com/accounts/ui/logo_2x.png"/>
</a>

Пропускает почти без изменений (к нему добавился атрибут rel="nofollow", что хорошо для пользовательского контента):

root@kitploit:~
<a href="http://www.google.com/" rel="nofollow">
  <img src="https://ssl.gstatic.com/accounts/ui/logo_2x.png"/>
</a>

Он защищает сайты от атак XSS. Существует множество векторов XSS-атак, и лучший способ снизить риск — очищать пользовательский ввод по известному безопасному списку HTML-элементов и атрибутов.

bluemonday следует всегда запускать после любой другой обработки.

Если вы используете blackfriday или Pandoc, то bluemonday следует запускать после этих шагов. Это гарантирует, что незащищённый HTML не появится позже в вашем процессе.

bluemonday во многом вдохновлён как OWASP Java HTML Sanitizer, так и HTML Purifier.

Техническая сводка

Основан на белом списке: вам нужно либо построить политику, описывающую HTML-элементы и атрибуты для разрешения (и regexp-шаблоны атрибутов), либо использовать одну из предоставленных политик с хорошими настройками по умолчанию.

Политика, содержащая белый список, применяется с помощью быстрого невалидирующего, однопроходного токенизирующего парсера, реализованного в библиотеке Go net/html основной командой Go.

Мы ожидаем корректно оформленный HTML (закрывающие элементы для каждого открытого элемента, правильная вложенность) и поэтому не занимаемся исправлением плохо вложенного или неполного HTML. Мы сосредоточены на том, чтобы все существующие элементы были описаны в белом списке политики, а атрибуты и ссылки были безопасны для использования на вашей веб-странице. Здесь действует принцип GIGO: если вы скормите ему плохой HTML, bluemonday не обязан придумывать, как сделать его снова хорошим.

Готов ли он к продакшену?

Да

Мы используем bluemonday в продакшене, перейдя с широко используемого и многократно проверенного в полевых условиях OWASP Java HTML Sanitizer.

Мы проходим наш обширный набор тестов (включая тесты AntiSamy, а также тесты на любые поднятые задачи). Проверьте нерешённые задачи, чтобы понять, не может ли что-то стать для вас препятствием.

Мы приглашаем pull request'ы и issues, чтобы помочь нам гарантировать всестороннюю защиту от различных атак через пользовательский контент.

Использование

Установите с помощью go get github.com/microcosm-cc/bluemonday

Затем вызовите его:

root@kitploit:~
package main

import (
	"fmt"

	"github.com/microcosm-cc/bluemonday"
)

func main() {
	// Do this once for each unique policy, and use the policy for the life of the program
	// Policy creation/editing is not safe to use in multiple goroutines
	p := bluemonday.UGCPolicy()

	// The policy can then be used to sanitize lots of input and it is safe to use the policy in multiple goroutines
	html := p.Sanitize(
		`<a onblur="alert(secret)" href="http://www.google.com">Google</a>`,
	)

	// Output:
	// <a href="http://www.google.com" rel="nofollow">Google</a>
	fmt.Println(html)
}

Мы предлагаем три способа вызова Sanitize:

root@kitploit:~
p.Sanitize(string) string
p.SanitizeBytes([]byte) []byte
p.SanitizeReader(io.Reader) bytes.Buffer

Если вы одержимы производительностью, p.SanitizeReader(r).Bytes() вернёт []byte без выполнения лишних преобразований входов или выходов. Хотя разница настолько незначительна, что вам никогда не придётся об этом беспокоиться.

Вы можете создавать собственные политики:

root@kitploit:~
package main

import (
	"fmt"

	"github.com/microcosm-cc/bluemonday"
)

func main() {
	p := bluemonday.NewPolicy()

	// Require URLs to be parseable by net/url.Parse and either:
	//   mailto: http:// or https://
	p.AllowStandardURLs()

	// We only allow <p> and <a href="">
	p.AllowAttrs("href").OnElements("a")
	p.AllowElements("p")

	html := p.Sanitize(
		`<a onblur="alert(secret)" href="http://www.google.com">Google</a>`,
	)

	// Output:
	// <a href="http://www.google.com">Google</a>
	fmt.Println(html)
}

Мы поставляем две политики по умолчанию:

  1. bluemonday.StrictPolicy() — её можно считать эквивалентом удаления всех HTML-элементов и их атрибутов, поскольку в её белом списке ничего нет. Пример сценария использования — заголовки записей в блоге, где HTML-теги не ожидаются вовсе, а если они есть, то и элементы, и их содержимое должны быть удалены. Это очень строгая политика.
  2. bluemonday.UGCPolicy() — допускает широкий набор HTML-элементов и атрибутов, безопасных для пользовательского контента. Обратите внимание: эта политика не разрешает iframe, object, embed, стили, script и т.д. Пример сценария использования — тело записи в блоге, где ожидается разнообразное форматирование, а также возможны TABLE и IMG.

Построение политики

Суть построения политики — определить, какие HTML-элементы и атрибуты считаются безопасными для вашего сценария. OWASP предоставляет шпаргалку по предотвращению XSS для объяснения рисков, но по сути:

  1. Избегайте всего, кроме стандартных HTML-элементов
  2. Избегайте элементов script, style, iframe, object, embed, base, которые позволяют клиенту выполнять код или включать сторонний контент, способный выполнять код
  3. Избегайте всего, кроме простых HTML-атрибутов, значения которых сопоставляются с регулярным выражением

По сути, вы должны быть в состоянии описать, какой HTML допустим для вашего сценария. Если вы не уверены, что можете описать свою политику, подумайте об использовании одной из поставляемых политик, например bluemonday.UGCPolicy().

Чтобы создать новую политику:

root@kitploit:~
p := bluemonday.NewPolicy()

Чтобы добавить элементы в политику, добавьте только элементы:

root@kitploit:~
p.AllowElements("b", "strong")

Или используйте регулярное выражение:

Примечание: если элемент добавляется по имени, как показано выше, любое подходящее регулярное выражение будет проигнорировано

Также рекомендуется следить, чтобы несколько шаблонов не перекрывались, поскольку порядок выполнения не гарантируется и это может привести к пропуску некоторых правил.

root@kitploit:~
p.AllowElementsMatching(regex.MustCompile(`^my-element-`))

Или добавляйте элементы путём добавления атрибута:

root@kitploit:~
// Note the recommended pattern, see the recommendation on using .Matching() below
p.AllowAttrs("nowrap").OnElements("td", "th")

Опять же, здесь также поддерживается альтернативный вариант сопоставления по регулярному выражению:

root@kitploit:~
p.AllowAttrs("nowrap").OnElementsMatching(regex.MustCompile(`^my-element-`))

Атрибуты можно добавлять либо ко всем элементам:

root@kitploit:~
p.AllowAttrs("dir").Matching(regexp.MustCompile("(?i)rtl|ltr")).Globally()

Либо атрибуты можно добавлять к конкретным элементам:

root@kitploit:~
// Not the recommended pattern, see the recommendation on using .Matching() below
p.AllowAttrs("value").OnElements("li")

Всегда рекомендуется задавать атрибуту сопоставление с шаблоном. Иначе XSS в HTML-атрибутах очень прост:

root@kitploit:~
// \p{L} matches unicode letters, \p{N} matches unicode numbers
p.AllowAttrs("title").Matching(regexp.MustCompile(`[\p{L}\p{N}\s\-_',:\[\]!\./\\\(\)&]*`)).Globally()

Вы можете остановиться в любой момент и вызвать .Sanitize():

root@kitploit:~
// string htmlIn passed in from a HTTP POST
htmlOut := p.Sanitize(htmlIn)

Вы также можете взять любую существующую политику и расширить её:

root@kitploit:~
p := bluemonday.UGCPolicy()
p.AllowElements("fieldset", "select", "option")

Встроенный CSS

Хотя обрабатывать встроенный CSS можно с помощью AllowAttrs с правилом Matching, написать единое монолитное регулярное выражение для безопасной обработки всего встроенного CSS, который вы хотите разрешить, — нетривиальная задача. Вместо того чтобы пытаться это сделать, вы можете разрешить атрибут style на любых нужных элементах и использовать стилевые политики для контроля и очистки встроенных стилей.

Настоятельно рекомендуется использовать Matching (с подходящим регулярным выражением), MatchingEnum или MatchingHandler, чтобы каждый стиль соответствовал вашим потребностям, но для большинства широко используемых стилей предусмотрены обработчики по умолчанию.

Как и в случае с атрибутами, вы можете разрешить задавать конкретные CSS-свойства во встроенных стилях:

root@kitploit:~
p.AllowAttrs("style").OnElements("span", "p")
// Allow the 'color' property with valid RGB(A) hex values only (on any element allowed a 'style' attribute)
p.AllowStyles("color").Matching(regexp.MustCompile("(?i)^#([0-9a-f]{3,4}|[0-9a-f]{6}|[0-9a-f]{8})$")).Globally()

Кроме того, вы можете разрешить устанавливать CSS-свойству только определённое допустимое значение:

root@kitploit:~
p.AllowAttrs("style").OnElements("span", "p")
// Allow the 'text-decoration' property to be set to 'underline', 'line-through' or 'none'
// on 'span' elements only
p.AllowStyles("text-decoration").MatchingEnum("underline", "line-through", "none").OnElements("span")

Или вы можете задавать элементы на основе сопоставления с регулярным выражением:

root@kitploit:~
p.AllowAttrs("style").OnElementsMatching(regex.MustCompile(`^my-element-`))
// Allow the 'text-decoration' property to be set to 'underline', 'line-through' or 'none'
// on 'span' elements only
p.AllowStyles("text-decoration").MatchingEnum("underline", "line-through", "none").OnElementsMatching(regex.MustCompile(`^my-element-`))

Если вам нужна более точная проверка, вы можете создать обработчик, который принимает строку и возвращает bool для проверки значений конкретного свойства. Строковый параметр уже преобразован в нижний регистр, а кодовые точки Unicode преобразованы.

root@kitploit:~
myHandler := func(value string) bool{
	// Validate your input here
	return true
}
p.AllowAttrs("style").OnElements("span", "p")
// Allow the 'color' property with values validated by the handler (on any element allowed a 'style' attribute)
p.AllowStyles("color").MatchingHandler(myHandler).Globally()

Ссылки

Ссылки — это сложные объекты для безопасной очистки, а также один из крупнейших векторов атак вредоносного контента.

Можно сделать так:

root@kitploit:~
p.AllowAttrs("href").Matching(regexp.MustCompile(`(?i)mailto|https?`)).OnElements("a")

Но это вас не защитит, так как в данном случае регулярного выражения недостаточно, чтобы предотвратить непредвиденные действия некорректного значения.

Мы предоставляем несколько дополнительных глобальных опций для безопасной работы со ссылками.

RequireParseableURLs гарантирует, что URL-адреса разбираются пакетом Go net/url:

root@kitploit:~
p.RequireParseableURLs(true)

Если вы включили разбираемые URL, то следующая опция будет AllowRelativeURLs. По умолчанию она отключена (bluemonday — это инструмент белых списков... вам нужно явно сказать нам, что разрешить), и при отключении она блокирует все локальные и схема-относительные URL (например, href="localpage.html", href="../home.html" и даже href="//www.google.com" являются относительными):

root@kitploit:~
p.AllowRelativeURLs(true)

Если вы включили разбираемые URL, вы можете разрешить допустимые схемы (обычно называемые протоколами, когда речь идёт об http и https). Имейте в виду, что разрешение относительных URL в предыдущей опции допускает пустую схему:

root@kitploit:~
p.AllowURLSchemes("mailto", "http", "https")

Независимо от того, включили ли вы разбираемые URL, вы можете принудительно задать всем URL атрибут rel="nofollow". Он будет добавлен, если его нет, но только когда href корректен:

root@kitploit:~
// This applies to "a" "area" "link" elements that have a "href" attribute
p.RequireNoFollowOnLinks(true)

Аналогично, вы можете принудительно указать noreferrer в атрибуте rel всех URL.

root@kitploit:~
// This applies to "a" "area" "link" elements that have a "href" attribute
p.RequireNoReferrerOnLinks(true)

Мы предоставляем удобный метод, который применяет всё вышеперечисленное, но вам всё равно нужно разрешить связываемые элементы, к которым будут применяться правила URL:

root@kitploit:~
p.AllowStandardURLs()
p.AllowAttrs("cite").OnElements("blockquote", "q")
p.AllowAttrs("href").OnElements("a", "area")
p.AllowAttrs("src").OnElements("img")

Дополнительная сложность, связанная со ссылками, — это data URI, определённый в RFC2397. Data URI позволяет встраивать изображения в таком формате:

root@kitploit:~
<img src="data:image/webp;base64,UklGRh4AAABXRUJQVlA4TBEAAAAvAAAAAAfQ//73v/+BiOh/AAA=">

Мы предоставили вспомогательный метод для проверки mimetype и следующего за ним base64-содержимого ссылок data URI:

root@kitploit:~
p.AllowDataURIImages()

Этот вспомогательный метод включит изображения GIF, JPEG, PNG и WEBP.

Следует отметить, что использование data URI ссылок несёт потенциальный риск для безопасности. Включайте data URI ссылки, только если вы уже доверяете содержимому.

У нас также есть несколько функций для работы с пользовательским контентом:

root@kitploit:~
p.AddTargetBlankToFullyQualifiedLinks(true)

Это гарантирует, что полностью квалифицированные якорные ссылки <a href="" /> (адрес href содержит имя хоста) получат добавленный атрибут target="_blank".

Кроме того, любая ссылка, у которой после применения политики есть target="_blank", получит также скорректированный атрибут rel с добавлением noopener. Это означает, что ссылка может изначально выглядеть как <a href="//host/path"/> и в итоге стать <a href="//host/path" rel="noopener" target="_blank">. Важно отметить, что добавление noopener — это функция безопасности, а не проблема. К сожалению, браузеры устроены так, что окно, открытое с помощью target="_blank", всё ещё может управлять окном-открывателем (вашей веб-страницей), и эта функция защищает от этого. Подробнее об этом можно прочитать здесь: https://dev.to/ben/the-targetblank-vulnerability-by-example

Вспомогательные методы построения политики

Мы также включаем несколько вспомогательных функций для упрощения построения политик:

root@kitploit:~

// Permits the "dir", "id", "lang", "title" attributes globally
p.AllowStandardAttributes()

// Permits the "img" element and its standard attributes
p.AllowImages()

// Permits ordered and unordered lists, and also definition lists
p.AllowLists()

// Permits HTML tables and all applicable elements and non-styling attributes
p.AllowTables()

Недопустимые инструкции

Следующее недопустимо:

root@kitploit:~
// This does not say where the attributes are allowed, you need to add
// .Globally() or .OnElements(...)
// This will be ignored without error.
p.AllowAttrs("value")

// This does not say where the attributes are allowed, you need to add
// .Globally() or .OnElements(...)
// This will be ignored without error.
p.AllowAttrs(
	"type",
).Matching(
	regexp.MustCompile("(?i)^(circle|disc|square|a|A|i|I|1)$"),
)

Оба примера демонстрируют одну и ту же проблему: они объявляют атрибуты, но затем не указывают, разрешены ли они глобально или только на конкретных элементах (и на каких). Атрибуты принадлежат одному или нескольким элементам, и политика должна объявлять это.

Ограничения

Мы пока не включаем инструменты для разрешения и очистки CSS. Это означает, что если вы не хотите делать всю тяжёлую работу в одном регулярном выражении (что не рекомендуется), вам не следует разрешать атрибут "style" где бы то ни было.

В той же теме оба элемента <script> и <style> считаются вредоносными. Эти элементы (и их содержимое) по умолчанию не отображаются, и для их разрешения требуется явно установить p.AllowUnsafe(true). Следует понимать, что разрешение этих элементов сводит на нет цель использования HTML-санитайзера, так как вы явно разрешаете либо JavaScript (и любой явно написанный XSS), либо CSS (который может изменить DOM для вставки JS). Кроме того, ограничения этой библиотеки означают, что она не знает, правильно ли структурирован HTML, и это может позволить этим элементам обойти некоторые механизмы безопасности, встроенные в стандарт парсера HTML WhatWG.

Задача bluemonday — не исправлять ваш плохой HTML, а лишь не пропускать вредоносный HTML. Если у вас есть непарные HTML-элементы или несоответствующая вложенность элементов, они останутся. Но если у вас корректно структурированный HTML, bluemonday его не сломает.

TODO

  • Выяснить, хотят ли разработчики возможность чёрного списка элементов и атрибутов. Это позволило бы разработчикам взять существующую политику (например, bluemonday.UGCPolicy()), которая покрывает 90% их потребностей, но делает больше, чем нужно, и удалить лишнее, чтобы сделать её на 100% соответствующей их желаниям
  • Исследовать, хотят ли разработчики валидирующий режим HTML, в котором HTML-элементы не просто преобразуются в сбалансированное дерево (каждый открывающий тег имеет закрывающий тег на правильной глубине), но и элементы и символьные данные появляются только в своём допустимом контексте (например, элемент table не является потомком caption, разрешены colgroup, thead, tbody, tfoot и tr, а символьные данные не допускаются)

Долгосрочные цели

  1. Открыть код для атакующего рецензирования, аналогичного Правилам атакующего рецензирования
  2. Собрать средства и оплатить внешний аудит безопасности
Скачать инструмент