Новое в Symfony 6.1: компонент HtmlSanitizer
13034

Новое в Symfony 6.1: компонент HtmlSanitizer


Веб-приложениям часто приходится работать с HTML-содержимым, созданным пользователями. Сделать это безопасным способом довольно сложно. Рендеринг этих небезопасных HTML-содержимых в шаблоне Twig или внедрение их через JavaScript в свойство innerHTML элементов может привести к нежелательному и опасному выполнению кода JavaScript.

Очистка HTML - это "процесс изучения HTML-документа и создания нового HTML-документа, в котором сохраняются только те теги или атрибуты, которые считаются безопасными и необходимыми".

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

<!-- an example of a wrong HTML input provided by the user -->
Original: <div><em>foo</div>
<!-- the best solution to fix this HTML code is to add the missing tag -->
Sanitized: <div><em>foo</em></div>

<!-- however, if the HTML error appears in other elements, the fix could be different -->
Original: <textarea><em>foo</textarea>
<!-- the best solution in this case is to HTML encode the wrong tag -->
Sanitized: <textarea>&lt;em&gt;foo</textarea>

В Symfony 6.1 мы добавляем санитайзер HTML на базе PHP, чтобы вы могли преобразовывать HTML-контент, созданный пользователем, в безопасный HTML-контент. Этот новый компонент похож на готовящийся W3C HTML Sanitizer API, и мы даже используем те же имена методов, когда это возможно, чтобы облегчить процесс обучения.

use Symfony\Component\HtmlSanitizer\HtmlSanitizerConfig;

// By default, any elements not included in the allowed or blocked elements
// will be dropped, including its children
$config = (new HtmlSanitizerConfig())
    // Allow "safe" elements and attributes. All scripts will be removed
    // as well as other dangerous behaviors like CSS injection
    ->allowSafeElements()

    // Allow the "div" element and no attribute can be on it
    ->allowElement('div')

    // Allow the "a" element, and the "title" attribute to be on it
    ->allowElement('a', ['title'])

    // Allow the "span" element, and any attribute from the Sanitizer API is allowed
    // (see https://wicg.github.io/sanitizer-api/#default-configuration)
    ->allowElement('span', '*')

    // Drop the "div" element: this element will be removed, including its children
    ->dropElement('div')
;

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

$config = (new HtmlSanitizerConfig())
    // ...

    // Forcefully set the value of all "rel" attributes on "a"
    // elements to "noopener noreferrer"
    ->forceAttribute('a', 'rel', 'noopener noreferrer')

    // Drop the "data-custom-attr" attribute from all elements:
    // this attribute will be removed
    ->dropAttribute('data-custom-attr', '*')

    // Transform all HTTP schemes to HTTPS
    ->forceHttpsUrls()

    // Configure which hosts are allowed in img/audio/video/iframe (by default all are allowed)
    ->allowedMediaHosts(['youtube.com', 'example.com'])
;

Помимо этих, существует множество других вариантов конфигурации. Ознакомьтесь с документацией по пакету HtmlSanitizer. После настройки используйте санитайзер следующим образом:

use Symfony\Component\HtmlSanitizer\HtmlSanitizer;

$sanitizer = new HtmlSanitizer($config);

// this sanitizes contents in the <body> context, removing any tags that are
// only allowed inside the <head> element
$sanitizer->sanitize($userInput);

// this sanitizes contents to include them inside a <head> tag
$sanitizer->sanitizeFor('head', $userInput);

// this sanitizes contents in the best way possible for the HTML element
// provided as the first argument (sometimes it will add missing tags and
// other times it will HTML-encode the unclosed tags)
$sanitizer->sanitizeFor('textarea', $userInput); // it will encode as HTML entities
$sanitizer->sanitizeFor('div', $userInput);      // it will sanitize same as <body>