HTML Sanitizer

Дата оновлення перекладу 2024-06-07

HTML Sanitizer

Компонент Sanitizer HTML має на меті дезінфекцію/очишення ненадійного HTML-коду (наприклад, створеного редактором WYSIWYG у браузері) в HTML, якому можна довіряти. Він заснований на Пропозиції стандарту Дезінфектора HTML W3C.

Дезінфектор HTML створює нову структуру HTML з нуля, беручи тільки елементи та атрибути, які дозволені конфігурацією. Це означає, що зворотний HTML дуже передбачуваний (містить лише дозволені елементи), але не дуже добре працює з погано відформатованим введенням (наприклад, невалідним HTML). Дезінфектор призначається для двох випадків використання:

  • Запобігання атакам безпеки, заснованим на XSS або інших технологіях, що покладаються на виконання зловмисного коду у браузерах відвідувачів;
  • Генерування HTML, який завжди поважає певний формат (тільки певні теги, атрибути, хости і т.д.), щоб мати змогу стійко стилізувати результуюче виведення з CSS. Це також захищає ваш додаток від атак, повʼязаних з, наприклад, зміною CSS всієї сторінки.

Установка

Ви можете встановити компонент Дезінфектор HTML за допомогою:

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);
        // ... proceed using the safe HTML
    }
}

Note

Конфігурація дезінфектора HTML за замовчуванням дозволяє всі "безпечні" елементи та атрибути, як визначено Пропозицією стандарту W3C. На практиці, це означає, що результуючий код не міститиме ніяких скриптів, стилів або інших елементів, які можуть викликати дивну поведінку або вигляд сайту. Пізніше у цій статті ви дізнаєтеся, як повністю налаштовувати дезінфектор 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 напряму інтегррується з Формами Symfony, щоб дезінфекувати введення форми до його обробки вашим додатком.

Ви можете включити дезінфектор у формах 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. Цей сервіс буде автозмонтований для сервісів, які мають параметр HtmlSanitizerInterface $appPostSanitizer.

Дозвівл базових ліній елементів

Ви можете розпочати користувацький дезінфектор HTML з використання однієї з двох базових ліній:

Статичні елементи
Всі елементи та трибути на базовій лінії дозволяють списки із Пропозіції стандарту W3C (це не включає в себе скрипти).
Безпечні елементи
Всі елементи та атрибути зі списку "статичних елементів", за виключенням елементів та атрибутів, які такоож можуть призвети до впровадження/клік-джекінгу 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 - дозволені.

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
# config/packages/html_sanitizer.yaml
framework:
    html_sanitizer:
        sanitizers:
            app.post_sanitizer:
                # ...

                # якщо `true`, всі URLs будуть форсовані з використанням схеми `https://` (замість,
                # наприклад, `http://` або `mailto:`)
                force_https_urls: true

                # вказує дозволені схеми URL. Якщо URL має іншу схему, атрибут
                # буде впущено
                allowed_link_schemes: ['http', 'https', 'mailto']

                # вказує дозволені хости, атрибут буде впущено, якщо URL
                # містить інший хост
                allowed_link_hosts: ['symfony.com']

                # дозволяти відносні посилання, чи ні (тобто, URL без схеми та хосту)
                allow_relative_links: true

Форсування/дозвіл медіа URL

Як і з URL посилань , ви також можете контролювати URL інших медіа в HTML. Наступні атрибути перевіряються дезінфектором HTML: src, 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
# config/packages/html_sanitizer.yaml
framework:
    html_sanitizer:
        sanitizers:
            app.post_sanitizer:
                # ...

                # якщо `true`, всі URL будуть форсовані з використанням схеми `https://` (замість,
                # наприклад, `http://` або `data:`)
                force_https_urls: true

                # вказує дозволені схеми URL. Якщо URL має іншу схему, атрибут
                # буде впущено
                allowed_media_schemes: ['http', 'https', 'mailto']

                # вказує дозволені хости, атрибут буде впущено, якщо URL
                # містить інший хост
                allowed_media_hosts: ['symfony.com']

                # дозволяти відносні посилання, чи ні (тобто, 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