Skip to content

Commit 9928a9b

Browse files
committed
Start with HTML Sanitizer documentation
1 parent a686a02 commit 9928a9b

File tree

1 file changed

+235
-0
lines changed

1 file changed

+235
-0
lines changed

html_sanitizer.rst

Lines changed: 235 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,235 @@
1+
HTML Sanitizer
2+
==============
3+
4+
.. versionadded:: 6.1
5+
6+
The HTML Sanitizer component was introduced in Symfony 6.1.
7+
8+
The HTML Sanitizer components aims at sanitizing/cleaning untrusted HTML
9+
code (e.g. created by a WYSIWYG editor in the browser) into HTML that can
10+
be trusted. It is based on the `HTML Sanitizer W3C Standard Proposal`_.
11+
12+
The HTML sanitizer creates a new HTML structure from scratch, taking only
13+
the elements and attributes that are allowed (by configuration). This means
14+
that the returned HTML very predicatable (it only contains allowed
15+
elements), but it does not work well with badly formatted input (e.g.
16+
invalid HTML). The sanitizer is targetted for two use-cases:
17+
18+
* Preventing security attacks based on XSS or other technologies relying on
19+
execution of malicious code on the visitors browsers;
20+
* Generating HTML that always respect a certain format (only certain
21+
tags, attributes, hosts, etc.) to be able to consistently style the
22+
resulting output with CSS. This also protects your application against
23+
attacks related to e.g. changing the CSS of the whole page.
24+
25+
Installation
26+
------------
27+
28+
You can install the HTML Sanitizer component with:
29+
30+
.. code-block:: terminal
31+
32+
$ composer require symfony/http-client
33+
34+
Basic Usage
35+
-----------
36+
37+
Use the :class:`Symfony\\Component\\HtmlSanitizer\\HtmlSanitizer` class to
38+
sanitize the HTML. In the Symfony framework, this class is available as the
39+
``html_sanitizer`` service. This service will be :doc:`autowired </service_container/autowiring>`
40+
automatically when type-hinting for
41+
:class:`Symfony\\Contracts\\HtmlSanitizer\\HtmlSanitizerInterface`:
42+
43+
.. configuration-block::
44+
45+
.. code-block:: php-symfony
46+
47+
// src/Controller/BlogPostController.php
48+
namespace App\Controller;
49+
50+
// ...
51+
use Symfony\Contracts\HtmlSanitizer\HtmlSanitizerInterface;
52+
53+
class BlogPostController extends AbstractController
54+
{
55+
public function createAction(HTMLSanitizerInterface $htmlSanitizer, Request $request): Response
56+
{
57+
$unsafeContents = $request->request->get('post_contents');
58+
59+
$safeContents = $htmlSanitizer->sanitize($unsafeContents);
60+
// ... proceed using the safe HTML
61+
}
62+
}
63+
64+
.. code-block:: php-standalone
65+
66+
use Symfony\Contracts\HtmlSanitizer\HtmlSanitizer;
67+
use Symfony\Contracts\HtmlSanitizer\HtmlSanitizerConfig;
68+
69+
$htmlSanitizer = new HtmlSanitizer(
70+
(new HtmlSanitizerConfig())->allowSafeElements()
71+
);
72+
73+
// unsafe HTML (e.g. from a WYSIWYG editor in the browser)
74+
$unsafePostContents = ...;
75+
76+
$safePostContents = $htmlSanitizer->sanitize($unsafePostContents);
77+
// ... proceed using the safe HTML
78+
79+
.. note::
80+
81+
The default configuration of the HTML sanitizer allows all "safe"
82+
elements and attributes, as defined by the `W3C Standard Proposal`_. In
83+
practice, this means that the resulting code will not contain any
84+
scripts, styles or other elements that can cause the website to behave
85+
or look different. Later in this article, you'll learn how to
86+
:ref:`fully customize the HTML sanitizer <html-sanitizer-configuration>`.
87+
88+
Sanitizing HTML for a Specific Context
89+
--------------------------------------
90+
91+
The default :method:`Symfony\\Component\\HtmlSanitizer\\HtmlSanitizer::sanitize`
92+
method cleans the HTML code for usage in the ``<body>`` element. Using the
93+
:method:`Symfony\\Component\\HtmlSanitizer\\HtmlSanitizer::sanitizeFor`
94+
method, you can instruct HTML sanitizer to customize this for the
95+
``<head>`` or a more specific HTML tag::
96+
97+
// tags not allowed in <head> will be removed
98+
$safeInput = $htmlSanitizer->sanitizeFor('head', $userInput);
99+
100+
// encodes the returned HTML using HTML entities
101+
$safeInput = $htmlSanitizer->sanitizeFor('title', $userInput);
102+
$safeInput = $htmlSanitizer->sanitizeFor('textarea', $userInput);
103+
104+
// uses the <body> context, removing tags only allowed in <head>
105+
$safeInput = $htmlSanitizer->sanitizeFor('body', $userInput);
106+
$safeInput = $htmlSanitizer->sanitizeFor('section', $userInput);
107+
108+
.. _html-sanitizer-configuration:
109+
110+
Configuration
111+
-------------
112+
113+
The behavior of the HTML sanitizer can be fully customized. This allows you
114+
to explicitly state which elements, attributes and even attribute values
115+
are allowed.
116+
117+
You can do this by defining a new HTML sanitizer in the configuration:
118+
119+
.. configuration-block::
120+
121+
.. code-block:: yaml
122+
123+
# config/packages/html_sanitizer.yaml
124+
framework:
125+
html_sanitizer:
126+
sanitizers:
127+
app.post_sanitizer:
128+
block_elements:
129+
- h1
130+
131+
.. code-block:: xml
132+
133+
<!-- config/packages/html_sanitizer.xml -->
134+
<?xml version="1.0" encoding="UTF-8" ?>
135+
<container xmlns="http://symfony.com/schema/dic/services"
136+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
137+
xmlns:framework="http://symfony.com/schema/dic/symfony"
138+
xsi:schemaLocation="http://symfony.com/schema/dic/services
139+
https://symfony.com/schema/dic/services/services-1.0.xsd
140+
http://symfony.com/schema/dic/symfony https://symfony.com/schema/dic/symfony/symfony-1.0.xsd">
141+
142+
<framework:config>
143+
<framework:html-sanitizer>
144+
<framework:sanitizer name="app.post_sanitizer">
145+
<framework:block-element name="h1"/>
146+
</framework:sanitizer>
147+
</framework:html-sanitizer>
148+
</framework:config>
149+
</container>
150+
151+
.. code-block:: php
152+
153+
// config/packages/framework.php
154+
use Symfony\Config\FrameworkConfig;
155+
156+
return static function (FrameworkConfig $framework) {
157+
$framework->htmlSanitizer()
158+
->sanitizer('app.post_sanitizer')
159+
->blockElement('h1')
160+
;
161+
};
162+
163+
This configuration defines a new ``app.post_sanitizer`` service. This service
164+
will be :doc:`autowired </service_container/autowiring>` for services
165+
having an ``HtmlSanitizerInterface $appPostSanitizer`` parameter.
166+
167+
Allow Element Baselines
168+
~~~~~~~~~~~~~~~~~~~~~~~
169+
170+
allow_safe_elements: true
171+
allow_all_static_elements: true
172+
173+
Allow Elements
174+
~~~~~~~~~~~~~~
175+
176+
allow_elements:
177+
iframe: 'src'
178+
custom-tag: ['data-attr', 'data-attr-1']
179+
custom-tag-2: '*'
180+
181+
Block and Drop Elements
182+
~~~~~~~~~~~~~~~~~~~~~~~
183+
184+
block_elements:
185+
- section
186+
drop_elements:
187+
- video
188+
189+
Allow Attributes
190+
~~~~~~~~~~~~~~~~
191+
192+
allow_attributes:
193+
src: ['iframe']
194+
data-attr: '*'
195+
196+
Drop Attributes
197+
~~~~~~~~~~~~~~~
198+
199+
drop_attributes:
200+
data-attr: [custom-tag]
201+
data-attr-1: []
202+
data-attr-2: '*'
203+
204+
Force Attribute Values
205+
~~~~~~~~~~~~~~~~~~~~~~
206+
207+
force_attributes:
208+
a:
209+
rel: noopener noreferrer
210+
h1:
211+
class: bp4-heading
212+
213+
Force/Allow Links
214+
~~~~~~~~~~~~~~~~~
215+
216+
force_https_urls: true
217+
allowed_link_schemes: ['http', 'https', 'mailto']
218+
allowed_link_hosts: ['symfony.com']
219+
allow_relative_links: true
220+
221+
Allow Media
222+
~~~~~~~~~~~
223+
224+
allowed_media_schemes: ['http', 'https', 'data']
225+
allowed_media_hosts: ['symfony.com']
226+
allow_relative_medias: true
227+
228+
Custom Attribute Sanitizers
229+
~~~~~~~~~~~~~~~~~~~~~~~~~~~
230+
231+
with_attribute_sanitizers:
232+
- App\Sanitizer\CustomAttributeSanitizer
233+
234+
_ `HTML Sanitizer W3C Standard Proposal`: https://wicg.github.io/sanitizer-api/
235+
_ `W3C Standard Proposal`: https://wicg.github.io/sanitizer-api/

0 commit comments

Comments
 (0)