HTML Sanitizer
Дата обновления перевода 2024-07-30
HTML Sanitizer
Компонент HTML Sanitizer предназначен для проверки/очистки ненадежного HTML кода (например, созданного WYSIWYG-редактором в браузере) в HTML, которому можно доверять. Он основан на HTML Sanitizer W3C Standard Proposal.
- Дезинфектор HTML создает новую структуру HTML с нуля, принимая только
- элементы и атрибуты, которые разрешены конфигурацией. Это означает.
что возвращаемый HTML очень предсказуем (он содержит только разрешенные элементы), но он не очень хорошо работает с плохо отформатированным вводом (например. невалидным HTML). Дезинфектор предназначен для двух случаев использования:
- Предотвращение атак безопасности, основанных на XSS или других технологиях, полагающихся на выполнение вредоносного кода в браузере посетителя;
- Генерация HTML, который всегда соблюдает определенный формат (только определенные теги, атрибуты, хосты и т.д.), чтобы иметь возможность последовательно стилизовать полученный результат с помощью CSS. Это также защищает ваше приложение от атак, связанных, например, с изменением CSS всей страницы.
Установка
Вы можете установить компонент HTML Sanitizer с помощью:
1
$ composer require symfony/html-sanitizer
Базовое использование
Используйте класс HtmlSanitizer для
для дезинфекции HTML. Во фреймворке Symfony этот класс доступен как
сервис html_sanitizer
. Этот сервис будет автосмонтирован`
при использовании подсказки типов для
HtmlSanitizerInterface:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
// src/Controller/BlogPostController.php
namespace App\Controller;
// ...
use Symfony\Component\HtmlSanitizer\HtmlSanitizerInterface;
class BlogPostController extends AbstractController
{
public function createAction(HtmlSanitizerInterface $htmlSanitizer, Request $request): Response
{
$unsafeContents = $request->getPayload()->get('post_contents');
$safeContents = $htmlSanitizer->sanitize($unsafeContents);
// ... продолжать использовать безопасный HTML
}
}
Note
Конфигурация по умолчанию дезинфектора HTML позволяет использовать все "безопасные" элементы и атрибуты, как определено в W3C Standard Proposal. На практике это означает, что полученный код не будет содержать никаких скриптов, стилей или других элементов, которые могут заставить сайт вести себя или выглядеть по-другому. Позже в этой статье вы узнаете, как полностью настраивать HTML-дезинфектор .
Дезинфекция HTML для конкретного контекста
Метод по умолчанию sanitize()
очищает HTML-код для использования в элементе <body>
. Используя метод
sanitizeFor()
вы можете указать дезинфектору HTML настраивать это для
<head>
или более конкретного HTML-тега:
1 2 3 4 5 6 7 8 9 10
// теги, не разрешенные в <head>, будут удалены
$safeInput = $htmlSanitizer->sanitizeFor('head', $userInput);
// шифрует возвращенный HTML с использованием сущностей HTML
$safeInput = $htmlSanitizer->sanitizeFor('title', $userInput);
$safeInput = $htmlSanitizer->sanitizeFor('textarea', $userInput);
// использует контекст <body>, удаляя только теги, разрешенные в <head>
$safeInput = $htmlSanitizer->sanitizeFor('body', $userInput);
$safeInput = $htmlSanitizer->sanitizeFor('section', $userInput);
Дезинфекция HTML от ввода формы
Компонент HTML Sanitizer напрямую интегрируется с Symfony Forms,
для дезинфекции ввода формы перед его обработкой вашим приложением.
Вы можете включить дезинфектор в формах TextType
или любых формах, расширяющих
этот тип (например, TextareaType
), используя опцию sanitize_html
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
// src/Form/BlogPostType.php
namespace App\Form;
// ...
class BlogPostType extends AbstractType
{
// ...
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'sanitize_html' => true,
// использовать опцию "sanitizer", чтобы использовать пользовательский дезинфектор (см. ниже)
//'sanitizer' => 'app.post_sanitizer',
]);
}
}
Дезинфекция HTML в шаблонах Twig
Помимо дезинфекции пользовательского ввода, вы также можете дезинфицировать HTML-код перед
его выводом в шаблоне Twig, с помощью фильтра sanitize_html()
:
1 2 3 4
{{ post.body|sanitize_html }}
{# вы также можете использовать пользовательский дезинфектор (см. ниже) #}
{{ post.body|sanitize_html('app.post_sanitizer') }}
Конфигурация
Поведение HTML-дезинфектора может быть полностью настроено. Это позволяет вам явно указать, какие элементы, атрибуты и даже значения атрибутов разрешены.
Это можно сделать, определив новый HTML-дезинфектор в конфигурации:
1 2 3 4 5 6 7
# config/packages/html_sanitizer.yaml
framework:
html_sanitizer:
sanitizers:
app.post_sanitizer:
block_elements:
- h1
Эта конфигурация определяет новый сервис html_sanitizer.sanitizer.app.post_sanitizer
.
Этот сервис будет `.
Разрешить базовые значения элементов
Вы можете запустить пользовательский дезинфектор HTML, используя одну из двух базовых версий:
- Статические элементы
- Все элементы и атрибуты на базовой линии допускают списки из W3C Standard Proposal (сюда не входят скрипты).
- Безопасные элементы
- Все элементы и атрибуты из списка "статических элементов", исключая элементы и атрибуты, которые также могут привести к CSS внедрению/перехвату кликов.
1 2 3 4 5 6 7 8
# config/packages/html_sanitizer.yaml
framework:
html_sanitizer:
sanitizers:
app.post_sanitizer:
# включить одно из этого
allow_safe_elements: true
allow_static_elements: true
Разрешить элементы
Это добавляет элементы в список разрешенных. Для каждого элемента можно также указать разрешенные атрибуты этого элемента. Если они не указаны, то разрешены все атрибуты из W3C Standard Proposal.
1 2 3 4 5 6 7 8 9 10 11 12 13
# config/packages/html_sanitizer.yaml
framework:
html_sanitizer:
sanitizers:
app.post_sanitizer:
# ...
allow_elements:
# разрешить элемент <article> и 2 атрибута
article: ['class', 'data-attr']
# разрешить элемент <img> и сохранить атрибут src
img: 'src'
# разрешить элемент <h1> со всеми безопасными атрибутами
h1: '*'
Блокировать и скидывать элементы
Вы также можете блокировать (элемент будет удален, но его дочерние элементы будут сохранены) или сбрасывать (элемент и его дочерние элементы будут удалены).
Это также можно использовать для удаления элементов из списка разрешенных.
1 2 3 4 5 6 7 8 9 10 11
# config/packages/html_sanitizer.yaml
framework:
html_sanitizer:
sanitizers:
app.post_sanitizer:
# ...
# удалить <div>, но обработать дочерние
block_elements: ['div']
# удалить <figure> и его дочерние элементы
drop_elements: ['figure']
Разрешить атрибуты
С помощью этой опции вы можете указать, какие атрибуты будут сохранены в возвращаемом HTML. Атрибут будет разрешен для заданных элементов или для всех элементов, разрешенных до этой настройки.
1 2 3 4 5 6 7 8 9 10 11 12
# config/packages/html_sanitizer.yaml
framework:
html_sanitizer:
sanitizers:
app.post_sanitizer:
# ...
allow_attributes:
# разрешить "src' в элементах <iframe>
src: ['iframe']
# разрешить "data-attr" во всех элементах, разрешенных на данный момент
data-attr: '*'
Сбросить атрибуты
Эта опция позволяет запретить атрибуты, которые были разрешены ранее.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
# config/packages/html_sanitizer.yaml
framework:
html_sanitizer:
sanitizers:
app.post_sanitizer:
# ...
allow_attributes:
# разрешить "data-attr" во всех безопасных элементах...
data-attr: '*'
drop_attributes:
# ...кроме элемента <section>
data-attr: ['section']
# запрещает "style' в любом разрешенном элементе
style: '*'
Форсировать значения атрибутов
С помощью этой опции вы можете принудительно установить атрибут с заданным значением в
элементе. Например, используйте следующую конфигурацию, чтобы всегда устанавливатьrel=«noopener noreferrer»
в каждом <a>
элементе (даже если исходный элемент не
содержал атрибута rel
):
1 2 3 4 5 6 7 8 9
# config/packages/html_sanitizer.yaml
framework:
html_sanitizer:
sanitizers:
app.post_sanitizer:
# ...
force_attributes:
a:
rel: noopener noreferrer
Форсировать/разрешить ссылки URL
Помимо разрешения/блокировки элементов и атрибутов, вы также можете управлять
URL- адресами элементов <a>
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
# config/packages/html_sanitizer.yaml
framework:
html_sanitizer:
sanitizers:
app.post_sanitizer:
# ...
# если `true`, все URL, использующие схему `http://`, будут преобразованы для
# использования схемы `https://` вместо этого. `http` все еще должен быть разрешен
# в `allowed_link_schemes`
force_https_urls: true
# указывает разрешенные схемы URL. Если URL имеет другую схему, атрибут
# будет отброшен
allowed_link_schemes: ['http', 'https', 'mailto']
# указывает разрешенные хосты, атрибут будет отброшен, если URL содержит
# другой хост. Субдомены разрешены: например, следующая конфигурация
# будет также позволять 'www.symfony.com', 'live.symfony.com', и т.д.
allowed_link_hosts: ['symfony.com']
# разрешать ли относительные ссылки (т.е. URL без схемы и хоста)
allow_relative_links: true
Форсировать/разрешить медиа URL
Подобно ссылкам на URL , вы также можете управлять
URL других носителей в HTML. Следующие атрибуты проверяются
дезинфектором HTML: rc
, href
, lowsrc
, background
и ``ping''.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
# config/packages/html_sanitizer.yaml
framework:
html_sanitizer:
sanitizers:
app.post_sanitizer:
# ...
# если `true`, все URL, использующие схему `http://`, будут преобразованы, чтобы
# использовать схему `https://` вместо этого. `http` все еще должен быть разрешен
# в `allowed_media_schemes`
force_https_urls: true
# указывает разрешенные схемы URL. Если URL имеет другую схему, атрибут
# будет отброшен
allowed_media_schemes: ['http', 'https', 'mailto']
# указывает разрешенные хосты, атрибут будет отброшен, если URL содержит
# другой хост, который не является субдоменом разрешенного хоста
allowed_media_hosts: ['symfony.com'] # Также разрешает любой субдомен (т.е. www.symfony.com)
# разрешать ли относительные URL (т.е. URL без схемы и хоста)
allow_relative_medias: true
Максимальная длина ввода
Для предотвращения DoS-атак, по умолчанию дезинфектор HTML ограничивает
длину текста ввода до 20000
символов (измеряется strlen($input)
). Все
содержание, превышающее эту длину, будет усечено. Используйте эту опцию, чтобы
увеличить или уменьшить это ограничение:
1 2 3 4 5 6 7 8 9
# config/packages/html_sanitizer.yaml
framework:
html_sanitizer:
sanitizers:
app.post_sanitizer:
# ...
# ввод длиннее (в символах), чем это значение, будет обрезан
max_input_length: 30000 # default: 20000
Можно отключить это ограничение длины, установив максимальную длину ввода в значение
-1
. Остерегайтесь, что это может подвергнуть ваше приложение DoS-атакам.
Пользовательские дезинфекторы атрибутов
Управление ссылками и медиа-URL осуществляется с помощью
UrlAttributeSanitizer.
Вы также можете реализовать свой собственный дезинфектор атрибутов, чтобы контролировать значение
других атрибутов в HTML. Создайте класс, реализующий
AttributeSanitizerInterface
и зарегистрируйте его как сервис. После этого используйте with_attribute_sanitizers
,
чтобы включить его для дезинфектора HTML:
1 2 3 4 5 6 7 8 9 10 11 12
# config/packages/html_sanitizer.yaml
framework:
html_sanitizer:
sanitizers:
app.post_sanitizer:
# ...
with_attribute_sanitizers:
- App\Sanitizer\CustomAttributeSanitizer
# вы также можете отключить ранее включенные пользовательские дезинфекторы атрибутов
#without_attribute_sanitizers:
# - App\Sanitizer\CustomAttributeSanitizer