sanitize 6.1.3 → 7.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/{HISTORY.md → CHANGELOG.md} +32 -14
- data/LICENSE +3 -1
- data/README.md +120 -238
- data/lib/sanitize/config/basic.rb +15 -15
- data/lib/sanitize/config/default.rb +45 -45
- data/lib/sanitize/config/relaxed.rb +136 -32
- data/lib/sanitize/config/restricted.rb +2 -2
- data/lib/sanitize/config.rb +12 -14
- data/lib/sanitize/css.rb +308 -308
- data/lib/sanitize/transformers/clean_cdata.rb +9 -9
- data/lib/sanitize/transformers/clean_comment.rb +9 -9
- data/lib/sanitize/transformers/clean_css.rb +59 -55
- data/lib/sanitize/transformers/clean_doctype.rb +15 -15
- data/lib/sanitize/transformers/clean_element.rb +220 -237
- data/lib/sanitize/version.rb +3 -1
- data/lib/sanitize.rb +38 -38
- data/test/common.rb +4 -3
- data/test/test_clean_comment.rb +26 -25
- data/test/test_clean_css.rb +14 -13
- data/test/test_clean_doctype.rb +21 -20
- data/test/test_clean_element.rb +258 -273
- data/test/test_config.rb +22 -21
- data/test/test_malicious_css.rb +20 -19
- data/test/test_malicious_html.rb +100 -99
- data/test/test_parser.rb +26 -25
- data/test/test_sanitize.rb +70 -69
- data/test/test_sanitize_css.rb +149 -114
- data/test/test_transformers.rb +81 -83
- metadata +14 -43
data/README.md
CHANGED
@@ -1,21 +1,10 @@
|
|
1
|
-
Sanitize
|
2
|
-
========
|
1
|
+
# Sanitize
|
3
2
|
|
4
|
-
Sanitize is an allowlist-based HTML and CSS sanitizer. It removes all HTML
|
5
|
-
and/or CSS from a string except the elements, attributes, and properties you
|
6
|
-
choose to allow.
|
3
|
+
Sanitize is an allowlist-based HTML and CSS sanitizer. It removes all HTML and/or CSS from a string except the elements, attributes, and properties you choose to allow.
|
7
4
|
|
8
|
-
Using a simple configuration syntax, you can tell Sanitize to allow certain HTML
|
9
|
-
elements, certain attributes within those elements, and even certain URL
|
10
|
-
protocols within attributes that contain URLs. You can also allow specific CSS
|
11
|
-
properties, @ rules, and URL protocols in elements or attributes containing CSS.
|
12
|
-
Any HTML or CSS that you don't explicitly allow will be removed.
|
5
|
+
Using a simple configuration syntax, you can tell Sanitize to allow certain HTML elements, certain attributes within those elements, and even certain URL protocols within attributes that contain URLs. You can also allow specific CSS properties, @ rules, and URL protocols in elements or attributes containing CSS. Any HTML or CSS that you don't explicitly allow will be removed.
|
13
6
|
|
14
|
-
Sanitize is based on the [Nokogiri HTML5 parser][nokogiri], which parses HTML
|
15
|
-
the same way modern browsers do, and [Crass][crass], which parses CSS the same
|
16
|
-
way modern browsers do. As long as your allowlist config only allows safe markup
|
17
|
-
and CSS, even the most malformed or malicious input will be transformed into
|
18
|
-
safe output.
|
7
|
+
Sanitize is based on the [Nokogiri HTML5 parser][nokogiri], which parses HTML the same way modern browsers do, and [Crass][crass], which parses CSS the same way modern browsers do. As long as your allowlist config only allows safe markup and CSS, even the most malformed or malicious input will be transformed into safe output.
|
19
8
|
|
20
9
|
[![Gem Version](https://badge.fury.io/rb/sanitize.svg)](http://badge.fury.io/rb/sanitize)
|
21
10
|
[![Tests](https://github.com/rgrove/sanitize/workflows/Tests/badge.svg)](https://github.com/rgrove/sanitize/actions?query=workflow%3ATests)
|
@@ -23,8 +12,7 @@ safe output.
|
|
23
12
|
[crass]:https://github.com/rgrove/crass
|
24
13
|
[nokogiri]:https://github.com/sparklemotion/nokogiri
|
25
14
|
|
26
|
-
Links
|
27
|
-
-----
|
15
|
+
## Links
|
28
16
|
|
29
17
|
* [Home](https://github.com/rgrove/sanitize/)
|
30
18
|
* [API Docs](https://rubydoc.info/github/rgrove/sanitize/Sanitize)
|
@@ -32,15 +20,13 @@ Links
|
|
32
20
|
* [Release History](https://github.com/rgrove/sanitize/releases)
|
33
21
|
* [Online Demo](https://sanitize-web.fly.dev/)
|
34
22
|
|
35
|
-
Installation
|
36
|
-
-------------
|
23
|
+
## Installation
|
37
24
|
|
38
25
|
```
|
39
26
|
gem install sanitize
|
40
27
|
```
|
41
28
|
|
42
|
-
Quick Start
|
43
|
-
-----------
|
29
|
+
## Quick Start
|
44
30
|
|
45
31
|
```ruby
|
46
32
|
require 'sanitize'
|
@@ -59,8 +45,7 @@ Sanitize::CSS.stylesheet(css, Sanitize::Config::RELAXED)
|
|
59
45
|
Sanitize::CSS.properties(css, Sanitize::Config::RELAXED)
|
60
46
|
```
|
61
47
|
|
62
|
-
Usage
|
63
|
-
-----
|
48
|
+
## Usage
|
64
49
|
|
65
50
|
Sanitize can sanitize the following types of input:
|
66
51
|
|
@@ -71,7 +56,7 @@ Sanitize can sanitize the following types of input:
|
|
71
56
|
* Standalone CSS stylesheets
|
72
57
|
* Standalone CSS properties
|
73
58
|
|
74
|
-
>
|
59
|
+
> [!WARNING]
|
75
60
|
>
|
76
61
|
> Sanitize cannot fully sanitize the contents of `<math>` or `<svg>` elements. MathML and SVG elements are [foreign elements](https://html.spec.whatwg.org/multipage/syntax.html#foreign-elements) that don't follow normal HTML parsing rules.
|
77
62
|
>
|
@@ -79,31 +64,26 @@ Sanitize can sanitize the following types of input:
|
|
79
64
|
|
80
65
|
### HTML Fragments
|
81
66
|
|
82
|
-
A fragment is a snippet of HTML that doesn't contain a root-level `<html>`
|
83
|
-
element.
|
67
|
+
A fragment is a snippet of HTML that doesn't contain a root-level `<html>` element.
|
84
68
|
|
85
|
-
If you don't specify any configuration options, Sanitize will use its strictest
|
86
|
-
settings by default, which means it will strip all HTML and leave only safe text
|
87
|
-
behind.
|
69
|
+
If you don't specify any configuration options, Sanitize will use its strictest settings by default, which means it will strip all HTML and leave only safe text behind.
|
88
70
|
|
89
71
|
```ruby
|
90
72
|
html = '<b><a href="http://foo.com/">foo</a></b><img src="bar.jpg">'
|
91
73
|
Sanitize.fragment(html)
|
92
|
-
# =>
|
74
|
+
# => "foo"
|
93
75
|
```
|
94
76
|
|
95
77
|
To keep certain elements, add them to the element allowlist.
|
96
78
|
|
97
79
|
```ruby
|
98
|
-
Sanitize.fragment(html, :
|
99
|
-
# =>
|
80
|
+
Sanitize.fragment(html, elements: ['b'])
|
81
|
+
# => "<b>foo</b>"
|
100
82
|
```
|
101
83
|
|
102
84
|
### HTML Documents
|
103
85
|
|
104
|
-
When sanitizing a document, the `<html>` element must be allowlisted. You can
|
105
|
-
also set `:allow_doctype` to `true` to allow well-formed document type
|
106
|
-
definitions.
|
86
|
+
When sanitizing a document, the `<html>` element must be allowlisted. You can also set `:allow_doctype` to `true` to allow well-formed document type definitions.
|
107
87
|
|
108
88
|
```ruby
|
109
89
|
html = %[
|
@@ -114,22 +94,15 @@ html = %[
|
|
114
94
|
]
|
115
95
|
|
116
96
|
Sanitize.document(html,
|
117
|
-
:
|
118
|
-
:
|
97
|
+
allow_doctype: true,
|
98
|
+
elements: ['html']
|
119
99
|
)
|
120
|
-
# =>
|
121
|
-
# <!DOCTYPE html><html>foo
|
122
|
-
#
|
123
|
-
# </html>
|
124
|
-
# ]
|
100
|
+
# => "<!DOCTYPE html><html>foo\n \n</html>"
|
125
101
|
```
|
126
102
|
|
127
103
|
### CSS in HTML
|
128
104
|
|
129
|
-
To sanitize CSS in an HTML fragment or document, first allowlist the `<style>`
|
130
|
-
element and/or the `style` attribute. Then allowlist the CSS properties,
|
131
|
-
@ rules, and URL protocols you wish to allow. You can also choose whether to
|
132
|
-
allow CSS comments or browser compatibility hacks.
|
105
|
+
To sanitize CSS in an HTML fragment or document, first allowlist the `<style>` element and/or the `style` attribute. Then allowlist the CSS properties, @ rules, and URL protocols you wish to allow. You can also choose whether to allow CSS comments or browser compatibility hacks.
|
133
106
|
|
134
107
|
```ruby
|
135
108
|
html = %[
|
@@ -142,11 +115,11 @@ html = %[
|
|
142
115
|
]
|
143
116
|
|
144
117
|
Sanitize.fragment(html,
|
145
|
-
:
|
146
|
-
:
|
118
|
+
elements: ['div', 'style'],
|
119
|
+
attributes: {'div' => ['style']},
|
147
120
|
|
148
|
-
:
|
149
|
-
:
|
121
|
+
css: {
|
122
|
+
properties: ['width']
|
150
123
|
}
|
151
124
|
)
|
152
125
|
#=> %[
|
@@ -161,8 +134,7 @@ Sanitize.fragment(html,
|
|
161
134
|
|
162
135
|
### Standalone CSS
|
163
136
|
|
164
|
-
Sanitize will happily clean up a standalone CSS stylesheet or property string
|
165
|
-
without needing to invoke the HTML parser.
|
137
|
+
Sanitize will happily clean up a standalone CSS stylesheet or property string without needing to invoke the HTML parser.
|
166
138
|
|
167
139
|
```ruby
|
168
140
|
css = %[
|
@@ -180,7 +152,6 @@ Sanitize::CSS.stylesheet(css, Sanitize::Config::RELAXED)
|
|
180
152
|
# => %[
|
181
153
|
#
|
182
154
|
#
|
183
|
-
#
|
184
155
|
# a { text-decoration: none; }
|
185
156
|
#
|
186
157
|
# a:hover {
|
@@ -197,15 +168,11 @@ Sanitize::CSS.properties(%[
|
|
197
168
|
#
|
198
169
|
# text-decoration: underline;
|
199
170
|
# ]
|
200
|
-
|
201
171
|
```
|
202
172
|
|
203
|
-
Configuration
|
204
|
-
-------------
|
173
|
+
## Configuration
|
205
174
|
|
206
|
-
In addition to the ultra-safe default settings, Sanitize comes with three other
|
207
|
-
built-in configurations that you can use out of the box or adapt to meet your
|
208
|
-
needs.
|
175
|
+
In addition to the ultra-safe default settings, Sanitize comes with three other built-in configurations that you can use out of the box or adapt to meet your needs.
|
209
176
|
|
210
177
|
### Sanitize::Config::RESTRICTED
|
211
178
|
|
@@ -213,16 +180,14 @@ Allows only very simple inline markup. No links, images, or block elements.
|
|
213
180
|
|
214
181
|
```ruby
|
215
182
|
Sanitize.fragment(html, Sanitize::Config::RESTRICTED)
|
216
|
-
# =>
|
183
|
+
# => "<b>foo</b>"
|
217
184
|
```
|
218
185
|
|
219
186
|
### Sanitize::Config::BASIC
|
220
187
|
|
221
188
|
Allows a variety of markup including formatting elements, links, and lists.
|
222
189
|
|
223
|
-
Images and tables are not allowed, links are limited to FTP, HTTP, HTTPS, and
|
224
|
-
mailto protocols, and a `rel="nofollow"` attribute is added to all links to
|
225
|
-
mitigate SEO spam.
|
190
|
+
Images and tables are not allowed, links are limited to FTP, HTTP, HTTPS, and mailto protocols, and a `rel="nofollow"` attribute is added to all links to mitigate SEO spam.
|
226
191
|
|
227
192
|
```ruby
|
228
193
|
Sanitize.fragment(html, Sanitize::Config::BASIC)
|
@@ -231,10 +196,7 @@ Sanitize.fragment(html, Sanitize::Config::BASIC)
|
|
231
196
|
|
232
197
|
### Sanitize::Config::RELAXED
|
233
198
|
|
234
|
-
Allows an even wider variety of markup, including images and tables, as well as
|
235
|
-
safe CSS. Links are still limited to FTP, HTTP, HTTPS, and mailto protocols,
|
236
|
-
while images are limited to HTTP and HTTPS. In this mode, `rel="nofollow"` is
|
237
|
-
not added to links.
|
199
|
+
Allows an even wider variety of markup, including images and tables, as well as safe CSS. Links are still limited to FTP, HTTP, HTTPS, and mailto protocols, while images are limited to HTTP and HTTPS. In this mode, `rel="nofollow"` is not added to links.
|
238
200
|
|
239
201
|
```ruby
|
240
202
|
Sanitize.fragment(html, Sanitize::Config::RELAXED)
|
@@ -243,50 +205,43 @@ Sanitize.fragment(html, Sanitize::Config::RELAXED)
|
|
243
205
|
|
244
206
|
### Custom Configuration
|
245
207
|
|
246
|
-
If the built-in modes don't meet your needs, you can easily specify a custom
|
247
|
-
configuration:
|
208
|
+
If the built-in modes don't meet your needs, you can easily specify a custom configuration:
|
248
209
|
|
249
210
|
```ruby
|
250
211
|
Sanitize.fragment(html,
|
251
|
-
:
|
212
|
+
elements: ['a', 'span'],
|
252
213
|
|
253
|
-
:
|
254
|
-
'a'
|
214
|
+
attributes: {
|
215
|
+
'a' => ['href', 'title'],
|
255
216
|
'span' => ['class']
|
256
217
|
},
|
257
218
|
|
258
|
-
:
|
219
|
+
protocols: {
|
259
220
|
'a' => {'href' => ['http', 'https', 'mailto']}
|
260
221
|
}
|
261
222
|
)
|
262
223
|
```
|
263
224
|
|
264
|
-
You can also start with one of Sanitize's built-in configurations and then
|
265
|
-
customize it to meet your needs.
|
225
|
+
You can also start with one of Sanitize's built-in configurations and then customize it to meet your needs.
|
266
226
|
|
267
|
-
The built-in configs are deeply frozen to prevent people from modifying them
|
268
|
-
(either accidentally or maliciously). To customize a built-in config, create a
|
269
|
-
new copy using `Sanitize::Config.merge()`, like so:
|
227
|
+
The built-in configs are deeply frozen to prevent people from modifying them (either accidentally or maliciously). To customize a built-in config, create a new copy using `Sanitize::Config.merge()`, like so:
|
270
228
|
|
271
229
|
```ruby
|
272
230
|
# Create a customized copy of the Basic config, adding <div> and <table> to the
|
273
231
|
# existing allowlisted elements.
|
274
232
|
Sanitize.fragment(html, Sanitize::Config.merge(Sanitize::Config::BASIC,
|
275
|
-
:
|
276
|
-
:
|
233
|
+
elements: Sanitize::Config::BASIC[:elements] + ['div', 'table'],
|
234
|
+
remove_contents: true
|
277
235
|
))
|
278
236
|
```
|
279
237
|
|
280
|
-
The example above adds the `<div>` and `<table>` elements to a copy of the
|
281
|
-
existing list of elements in `Sanitize::Config::BASIC`. If you instead want to
|
282
|
-
completely overwrite the elements array with your own, you can omit the `+`
|
283
|
-
operation:
|
238
|
+
The example above adds the `<div>` and `<table>` elements to a copy of the existing list of elements in `Sanitize::Config::BASIC`. If you instead want to completely overwrite the elements array with your own, you can omit the `+` operation:
|
284
239
|
|
285
240
|
```ruby
|
286
241
|
# Overwrite :elements instead of creating a copy with new entries.
|
287
242
|
Sanitize.fragment(html, Sanitize::Config.merge(Sanitize::Config::BASIC,
|
288
|
-
:
|
289
|
-
:
|
243
|
+
elements: ['div', 'table'],
|
244
|
+
remove_contents: true
|
290
245
|
))
|
291
246
|
```
|
292
247
|
|
@@ -294,66 +249,56 @@ Sanitize.fragment(html, Sanitize::Config.merge(Sanitize::Config::BASIC,
|
|
294
249
|
|
295
250
|
#### :add_attributes (Hash)
|
296
251
|
|
297
|
-
Attributes to add to specific elements. If the attribute already exists, it will
|
298
|
-
be replaced with the value specified here. Specify all element names and
|
299
|
-
attributes in lowercase.
|
252
|
+
Attributes to add to specific elements. If the attribute already exists, it will be replaced with the value specified here. Specify all element names and attributes in lowercase.
|
300
253
|
|
301
254
|
```ruby
|
302
|
-
:
|
255
|
+
add_attributes: {
|
303
256
|
'a' => {'rel' => 'nofollow'}
|
304
257
|
}
|
305
258
|
```
|
306
259
|
|
307
260
|
#### :allow_comments (boolean)
|
308
261
|
|
309
|
-
Whether or not to allow HTML comments. Allowing comments is strongly
|
310
|
-
discouraged, since IE allows script execution within conditional comments. The
|
311
|
-
default value is `false`.
|
262
|
+
Whether or not to allow HTML comments. Allowing comments is strongly discouraged, since IE allows script execution within conditional comments. The default value is `false`.
|
312
263
|
|
313
264
|
#### :allow_doctype (boolean)
|
314
265
|
|
315
|
-
Whether or not to allow well-formed HTML doctype declarations such as "<!DOCTYPE
|
316
|
-
html>" when sanitizing a document. This setting is ignored when sanitizing
|
317
|
-
fragments. The default value is `false`.
|
266
|
+
Whether or not to allow well-formed HTML doctype declarations such as "<!DOCTYPE html>" when sanitizing a document. This setting is ignored when sanitizing fragments. The default value is `false`.
|
318
267
|
|
319
268
|
#### :attributes (Hash)
|
320
269
|
|
321
|
-
Attributes to allow on specific elements. Specify all element names and
|
322
|
-
attributes in lowercase.
|
270
|
+
Attributes to allow on specific elements. Specify all element names and attributes in lowercase.
|
323
271
|
|
324
272
|
```ruby
|
325
|
-
:
|
326
|
-
'a'
|
273
|
+
attributes: {
|
274
|
+
'a' => ['href', 'title'],
|
327
275
|
'blockquote' => ['cite'],
|
328
|
-
'img'
|
276
|
+
'img' => ['alt', 'src', 'title']
|
329
277
|
}
|
330
278
|
```
|
331
279
|
|
332
|
-
If you'd like to allow certain attributes on all elements, use the symbol `:all`
|
333
|
-
instead of an element name.
|
280
|
+
If you'd like to allow certain attributes on all elements, use the symbol `:all` instead of an element name.
|
334
281
|
|
335
282
|
```ruby
|
336
283
|
# Allow the class attribute on all elements.
|
337
|
-
:
|
284
|
+
attributes: {
|
338
285
|
:all => ['class'],
|
339
|
-
'a'
|
286
|
+
'a' => ['href', 'title']
|
340
287
|
}
|
341
288
|
```
|
342
289
|
|
343
|
-
To allow arbitrary HTML5 `data-*` attributes, use the symbol `:data` in place of
|
344
|
-
an attribute name.
|
290
|
+
To allow arbitrary HTML5 `data-*` attributes, use the symbol `:data` in place of an attribute name.
|
345
291
|
|
346
292
|
```ruby
|
347
293
|
# Allow arbitrary HTML5 data-* attributes on <div> elements.
|
348
|
-
:
|
294
|
+
attributes: {
|
349
295
|
'div' => [:data]
|
350
296
|
}
|
351
297
|
```
|
352
298
|
|
353
299
|
#### :css (Hash)
|
354
300
|
|
355
|
-
Hash of the following CSS config settings to be used when sanitizing CSS (either
|
356
|
-
standalone or embedded in HTML).
|
301
|
+
Hash of the following CSS config settings to be used when sanitizing CSS (either standalone or embedded in HTML).
|
357
302
|
|
358
303
|
##### :css => :allow_comments (boolean)
|
359
304
|
|
@@ -361,36 +306,27 @@ Whether or not to allow CSS comments. The default value is `false`.
|
|
361
306
|
|
362
307
|
##### :css => :allow_hacks (boolean)
|
363
308
|
|
364
|
-
Whether or not to allow browser compatibility hacks such as the IE `*` and `_`
|
365
|
-
hacks. These are generally harmless, but technically result in invalid CSS. The
|
366
|
-
default is `false`.
|
309
|
+
Whether or not to allow browser compatibility hacks such as the IE `*` and `_` hacks. These are generally harmless, but technically result in invalid CSS. The default is `false`.
|
367
310
|
|
368
311
|
##### :css => :at_rules (Array or Set)
|
369
312
|
|
370
|
-
Names of CSS [at-rules][at-rules] to allow that may not have associated blocks,
|
371
|
-
such as `import` or `charset`. Names should be specified in lowercase.
|
313
|
+
Names of CSS [at-rules][at-rules] to allow that may not have associated blocks, such as `import` or `charset`. Names should be specified in lowercase.
|
372
314
|
|
373
315
|
[at-rules]:https://developer.mozilla.org/en-US/docs/Web/CSS/At-rule
|
374
316
|
|
375
317
|
##### :css => :at_rules_with_properties (Array or Set)
|
376
318
|
|
377
|
-
Names of CSS [at-rules][at-rules] to allow that may have associated blocks
|
378
|
-
containing CSS properties. At-rules like `font-face` and `page` fall into this
|
379
|
-
category. Names should be specified in lowercase.
|
319
|
+
Names of CSS [at-rules][at-rules] to allow that may have associated blocks containing CSS properties. At-rules like `font-face` and `page` fall into this category. Names should be specified in lowercase.
|
380
320
|
|
381
321
|
##### :css => :at_rules_with_styles (Array or Set)
|
382
322
|
|
383
|
-
Names of CSS [at-rules][at-rules] to allow that may have associated blocks
|
384
|
-
containing style rules. At-rules like `media` and `keyframes` fall into this
|
385
|
-
category. Names should be specified in lowercase.
|
323
|
+
Names of CSS [at-rules][at-rules] to allow that may have associated blocks containing style rules. At-rules like `media` and `keyframes` fall into this category. Names should be specified in lowercase.
|
386
324
|
|
387
325
|
##### :css => :import_url_validator
|
388
326
|
|
389
|
-
This is a `Proc` (or other callable object) that will be called and passed
|
390
|
-
the URL specified for any `@import` [at-rules][at-rules].
|
327
|
+
This is a `Proc` (or other callable object) that will be called and passed the URL specified for any `@import` [at-rules][at-rules].
|
391
328
|
|
392
|
-
You can use this to limit what can be imported, for example something
|
393
|
-
like the following to limit `@import` to Google Fonts URLs:
|
329
|
+
You can use this to limit what can be imported, for example something like the following to limit `@import` to Google Fonts URLs:
|
394
330
|
|
395
331
|
```ruby
|
396
332
|
Proc.new { |url| url.start_with?("https://fonts.googleapis.com") }
|
@@ -404,28 +340,26 @@ List of CSS property names to allow. Names should be specified in lowercase.
|
|
404
340
|
|
405
341
|
URL protocols to allow in CSS URLs. Should be specified in lowercase.
|
406
342
|
|
407
|
-
If you'd like to allow the use of relative URLs which don't have a protocol,
|
408
|
-
include the symbol `:relative` in the protocol array.
|
343
|
+
If you'd like to allow the use of relative URLs which don't have a protocol, include the symbol `:relative` in the protocol array.
|
409
344
|
|
410
345
|
#### :elements (Array or Set)
|
411
346
|
|
412
|
-
Array of HTML element names to allow. Specify all names in lowercase. Any
|
413
|
-
elements not in this array will be removed.
|
347
|
+
Array of HTML element names to allow. Specify all names in lowercase. Any elements not in this array will be removed.
|
414
348
|
|
415
349
|
```ruby
|
416
|
-
:
|
350
|
+
elements: %w[
|
417
351
|
a abbr b blockquote br cite code dd dfn dl dt em i kbd li mark ol p pre
|
418
352
|
q s samp small strike strong sub sup time u ul var
|
419
353
|
]
|
420
354
|
```
|
421
355
|
|
422
|
-
>
|
356
|
+
> [!WARNING]
|
423
357
|
>
|
424
358
|
> Sanitize cannot fully sanitize the contents of `<math>` or `<svg>` elements. MathML and SVG elements are [foreign elements](https://html.spec.whatwg.org/multipage/syntax.html#foreign-elements) that don't follow normal HTML parsing rules.
|
425
359
|
>
|
426
360
|
> By default, Sanitize will remove all MathML and SVG elements. If you add MathML or SVG elements to a custom element allowlist, you must assume that any content inside them will be allowed, even if that content would otherwise be removed or escaped by Sanitize. This may create a security vulnerability in your application.
|
427
361
|
|
428
|
-
>
|
362
|
+
> [!NOTE]
|
429
363
|
>
|
430
364
|
> Sanitize always removes `<noscript>` elements and their contents, even if `noscript` is in the allowlist.
|
431
365
|
>
|
@@ -433,10 +367,10 @@ elements not in this array will be removed.
|
|
433
367
|
|
434
368
|
#### :parser_options (Hash)
|
435
369
|
|
436
|
-
[Parsing options](https://
|
370
|
+
[Parsing options](https://nokogiri.org/tutorials/parsing_an_html5_document.html?h=parsing+options#parsing-options) to be supplied to Nokogiri.
|
437
371
|
|
438
372
|
```ruby
|
439
|
-
:
|
373
|
+
parser_options: {
|
440
374
|
max_errors: -1,
|
441
375
|
max_tree_depth: -1
|
442
376
|
}
|
@@ -444,81 +378,59 @@ elements not in this array will be removed.
|
|
444
378
|
|
445
379
|
#### :protocols (Hash)
|
446
380
|
|
447
|
-
URL protocols to allow in specific attributes. If an attribute is listed here
|
448
|
-
and contains a protocol other than those specified (or if it contains no
|
449
|
-
protocol at all), it will be removed.
|
381
|
+
URL protocols to allow in specific attributes. If an attribute is listed here and contains a protocol other than those specified (or if it contains no protocol at all), it will be removed.
|
450
382
|
|
451
383
|
```ruby
|
452
|
-
:
|
453
|
-
'a'
|
454
|
-
'img' => {'src'
|
384
|
+
protocols: {
|
385
|
+
'a' => {'href' => ['ftp', 'http', 'https', 'mailto']},
|
386
|
+
'img' => {'src' => ['http', 'https']}
|
455
387
|
}
|
456
388
|
```
|
457
389
|
|
458
|
-
If you'd like to allow the use of relative URLs which don't have a protocol,
|
459
|
-
include the symbol `:relative` in the protocol array:
|
390
|
+
If you'd like to allow the use of relative URLs which don't have a protocol, include the symbol `:relative` in the protocol array:
|
460
391
|
|
461
392
|
```ruby
|
462
|
-
:
|
393
|
+
protocols: {
|
463
394
|
'a' => {'href' => ['http', 'https', :relative]}
|
464
395
|
}
|
465
396
|
```
|
466
397
|
|
467
398
|
#### :remove_contents (boolean or Array or Set)
|
468
399
|
|
469
|
-
If this is `true`, Sanitize will remove the contents of any non-allowlisted
|
470
|
-
elements in addition to the elements themselves. By default, Sanitize leaves the
|
471
|
-
safe parts of an element's contents behind when the element is removed.
|
400
|
+
If this is `true`, Sanitize will remove the contents of any non-allowlisted elements in addition to the elements themselves. By default, Sanitize leaves the safe parts of an element's contents behind when the element is removed.
|
472
401
|
|
473
|
-
If this is an Array or Set of element names, then only the contents of the
|
474
|
-
specified elements (when filtered) will be removed, and the contents of all
|
475
|
-
other filtered elements will be left behind.
|
402
|
+
If this is an Array or Set of element names, then only the contents of the specified elements (when filtered) will be removed, and the contents of all other filtered elements will be left behind.
|
476
403
|
|
477
|
-
The default value
|
404
|
+
The default value can be seen in the [default config](lib/sanitize/config/default.rb).
|
478
405
|
|
479
406
|
#### :transformers (Array or callable)
|
480
407
|
|
481
|
-
Custom HTML transformer or array of custom transformers. See the Transformers
|
482
|
-
section below for details.
|
408
|
+
Custom HTML transformer or array of custom transformers. See the Transformers section below for details.
|
483
409
|
|
484
410
|
#### :whitespace_elements (Hash)
|
485
411
|
|
486
|
-
Hash of element names which, when removed, should have their contents surrounded
|
487
|
-
by whitespace to preserve readability.
|
412
|
+
Hash of element names which, when removed, should have their contents surrounded by whitespace to preserve readability.
|
488
413
|
|
489
|
-
Each element name is a key pointing to another Hash, which provides the specific
|
490
|
-
whitespace that should be inserted `:before` and `:after` the removed element's
|
491
|
-
position. The `:after` value will only be inserted if the removed element has
|
492
|
-
children, in which case it will be inserted after those children.
|
414
|
+
Each element name is a key pointing to another Hash, which provides the specific whitespace that should be inserted `:before` and `:after` the removed element's position. The `:after` value will only be inserted if the removed element has children, in which case it will be inserted after those children.
|
493
415
|
|
494
416
|
```ruby
|
495
|
-
:
|
496
|
-
'br'
|
497
|
-
'div' => { :
|
498
|
-
'p'
|
417
|
+
whitespace_elements: {
|
418
|
+
'br' => { before: "\n", after: "" },
|
419
|
+
'div' => { before: "\n", after: "\n" },
|
420
|
+
'p' => { before: "\n", after: "\n" }
|
499
421
|
}
|
500
422
|
```
|
501
423
|
|
502
|
-
The default elements with whitespace added before and after
|
503
|
-
|
504
|
-
```
|
505
|
-
address article aside blockquote br dd div dl dt
|
506
|
-
footer h1 h2 h3 h4 h5 h6 header hgroup hr li nav
|
507
|
-
ol p pre section ul
|
508
|
-
|
509
|
-
```
|
424
|
+
The default elements with whitespace added before and after can be seen in [the default config](lib/sanitize/config/default.rb).
|
510
425
|
|
511
426
|
## Transformers
|
512
427
|
|
513
|
-
Transformers allow you to filter and modify HTML nodes using your own custom
|
514
|
-
logic, on top of (or instead of) Sanitize's core filter. A transformer is any
|
515
|
-
object that responds to `call()` (such as a lambda or proc).
|
428
|
+
Transformers allow you to filter and modify HTML nodes using your own custom logic, on top of (or instead of) Sanitize's core filter. A transformer is any object that responds to `call()` (such as a lambda or proc).
|
516
429
|
|
517
|
-
To use one or more transformers, pass them to the `:transformers` config
|
518
|
-
setting. You may pass a single transformer or an array of transformers.
|
430
|
+
To use one or more transformers, pass them to the `:transformers` config setting. You may pass a single transformer or an array of transformers.
|
519
431
|
|
520
432
|
```ruby
|
521
|
-
Sanitize.fragment(html, :
|
433
|
+
Sanitize.fragment(html, transformers: [
|
522
434
|
transformer_one,
|
523
435
|
transformer_two
|
524
436
|
])
|
@@ -526,56 +438,31 @@ Sanitize.fragment(html, :transformers => [
|
|
526
438
|
|
527
439
|
### Input
|
528
440
|
|
529
|
-
Each transformer's `call()` method will be called once for each node in the HTML
|
530
|
-
(including elements, text nodes, comments, etc.), and will receive as an
|
531
|
-
argument a Hash that contains the following items:
|
441
|
+
Each transformer's `call()` method will be called once for each node in the HTML (including elements, text nodes, comments, etc.), and will receive as an argument a Hash that contains the following items:
|
532
442
|
|
533
443
|
* **:config** - The current Sanitize configuration Hash.
|
534
444
|
|
535
|
-
* **:is_allowlisted** - `true` if the current node has been allowlisted by a
|
536
|
-
previous transformer, `false` otherwise. It's generally bad form to remove
|
537
|
-
a node that a previous transformer has allowlisted.
|
445
|
+
* **:is_allowlisted** - `true` if the current node has been allowlisted by a previous transformer, `false` otherwise. It's generally bad form to remove a node that a previous transformer has allowlisted.
|
538
446
|
|
539
|
-
* **:node** - A `Nokogiri::XML::Node` object representing an HTML node. The
|
540
|
-
node may be an element, a text node, a comment, a CDATA node, or a document
|
541
|
-
fragment. Use Nokogiri's inspection methods (`element?`, `text?`, etc.) to
|
542
|
-
selectively ignore node types you aren't interested in.
|
447
|
+
* **:node** - A `Nokogiri::XML::Node` object representing an HTML node. The node may be an element, a text node, a comment, a CDATA node, or a document fragment. Use Nokogiri's inspection methods (`element?`, `text?`, etc.) to selectively ignore node types you aren't interested in.
|
543
448
|
|
544
|
-
* **:node_allowlist** - Set of `Nokogiri::XML::Node` objects in the current
|
545
|
-
document that have been allowlisted by previous transformers, if any. It's
|
546
|
-
generally bad form to remove a node that a previous transformer has
|
547
|
-
allowlisted.
|
449
|
+
* **:node_allowlist** - Set of `Nokogiri::XML::Node` objects in the current document that have been allowlisted by previous transformers, if any. It's generally bad form to remove a node that a previous transformer has allowlisted.
|
548
450
|
|
549
|
-
* **:node_name** - The name of the current HTML node, always lowercase (e.g.
|
550
|
-
"div" or "span"). For non-element nodes, the name will be something like
|
551
|
-
"text", "comment", "#cdata-section", "#document-fragment", etc.
|
451
|
+
* **:node_name** - The name of the current HTML node, always lowercase (e.g. "div" or "span"). For non-element nodes, the name will be something like "text", "comment", "#cdata-section", "#document-fragment", etc.
|
552
452
|
|
553
453
|
### Output
|
554
454
|
|
555
|
-
A transformer doesn't have to return anything, but may optionally return a Hash,
|
556
|
-
which may contain the following items:
|
455
|
+
A transformer doesn't have to return anything, but may optionally return a Hash, which may contain the following items:
|
557
456
|
|
558
|
-
* **:node_allowlist** - Array or Set of specific `Nokogiri::XML::Node`
|
559
|
-
objects to add to the document's allowlist, bypassing the current Sanitize
|
560
|
-
config. These specific nodes and all their attributes will be allowlisted,
|
561
|
-
but their children will not be.
|
457
|
+
* **:node_allowlist** - Array or Set of specific `Nokogiri::XML::Node` objects to add to the document's allowlist, bypassing the current Sanitize config. These specific nodes and all their attributes will be allowlisted, but their children will not be.
|
562
458
|
|
563
|
-
If a transformer returns anything other than a Hash, the return value will be
|
564
|
-
ignored.
|
459
|
+
If a transformer returns anything other than a Hash, the return value will be ignored.
|
565
460
|
|
566
461
|
### Processing
|
567
462
|
|
568
|
-
Each transformer has full access to the `Nokogiri::XML::Node` that's passed into
|
569
|
-
it and to the rest of the document via the node's `document()` method. Any
|
570
|
-
changes made to the current node or to the document will be reflected instantly
|
571
|
-
in the document and passed on to subsequently called transformers and to
|
572
|
-
Sanitize itself. A transformer may even call Sanitize internally to perform
|
573
|
-
custom sanitization if needed.
|
463
|
+
Each transformer has full access to the `Nokogiri::XML::Node` that's passed into it and to the rest of the document via the node's `document()` method. Any changes made to the current node or to the document will be reflected instantly in the document and passed on to subsequently called transformers and to Sanitize itself. A transformer may even call Sanitize internally to perform custom sanitization if needed.
|
574
464
|
|
575
|
-
Nodes are passed into transformers in the order in which they're traversed.
|
576
|
-
Sanitize performs top-down traversal, meaning that nodes are traversed in the
|
577
|
-
same order you'd read them in the HTML, starting at the top node, then its first
|
578
|
-
child, and so on.
|
465
|
+
Nodes are passed into transformers in the order in which they're traversed. Sanitize performs top-down traversal, meaning that nodes are traversed in the same order you'd read them in the HTML, starting at the top node, then its first child, and so on.
|
579
466
|
|
580
467
|
```ruby
|
581
468
|
html = %[
|
@@ -594,81 +481,76 @@ transformer = lambda do |env|
|
|
594
481
|
end
|
595
482
|
|
596
483
|
# Prints "header", "span", "strong", "p", "footer".
|
597
|
-
Sanitize.fragment(html, :
|
484
|
+
Sanitize.fragment(html, transformers: transformer)
|
598
485
|
```
|
599
486
|
|
600
|
-
Transformers have a tremendous amount of power, including the power to
|
601
|
-
completely bypass Sanitize's built-in filtering. Be careful! Your safety is in
|
602
|
-
your own hands.
|
487
|
+
Transformers have a tremendous amount of power, including the power to completely bypass Sanitize's built-in filtering. Be careful! Your safety is in your own hands.
|
603
488
|
|
604
489
|
### Example: Transformer to allow image URLs by domain
|
605
490
|
|
606
|
-
The following example demonstrates how to remove image elements unless they use
|
607
|
-
a relative URL or are hosted on a specific domain. It assumes that the `<img>`
|
608
|
-
element and its `src` attribute are already allowlisted.
|
491
|
+
The following example demonstrates how to remove image elements unless they use a relative URL or are hosted on a specific domain. It assumes that the `<img>` element and its `src` attribute are already allowlisted.
|
609
492
|
|
610
493
|
```ruby
|
611
|
-
require
|
494
|
+
require "uri"
|
612
495
|
|
613
496
|
image_allowlist_transformer = lambda do |env|
|
614
497
|
# Ignore everything except <img> elements.
|
615
|
-
return unless env[:node_name] ==
|
498
|
+
return unless env[:node_name] == "img"
|
616
499
|
|
617
|
-
node
|
618
|
-
image_uri = URI.parse(node[
|
500
|
+
node = env[:node]
|
501
|
+
image_uri = URI.parse(node["src"])
|
619
502
|
|
620
503
|
# Only allow relative URLs or URLs with the example.com domain. The
|
621
504
|
# image_uri.host.nil? check ensures that protocol-relative URLs like
|
622
|
-
# "//evil.com/foo.jpg".
|
623
|
-
unless image_uri.host ==
|
624
|
-
|
505
|
+
# "//evil.com/foo.jpg" are not allowed.
|
506
|
+
unless image_uri.host == "example.com"
|
507
|
+
unless image_uri.host.nil? && image_uri.relative?
|
508
|
+
node.unlink # `Nokogiri::XML::Node#unlink` removes a node from the document
|
509
|
+
end
|
625
510
|
end
|
626
511
|
end
|
627
512
|
```
|
628
513
|
|
629
514
|
### Example: Transformer to allow YouTube video embeds
|
630
515
|
|
631
|
-
The following example demonstrates how to create a transformer that will safely
|
632
|
-
allow valid YouTube video embeds without having to allow other kinds of embedded
|
633
|
-
content, which would be the case if you tried to do this by just allowing all
|
634
|
-
`<iframe>` elements:
|
516
|
+
The following example demonstrates how to create a transformer that will safely allow valid YouTube video embeds without having to allow other kinds of embedded content, which would be the case if you tried to do this by just allowing all `<iframe>` elements:
|
635
517
|
|
636
518
|
```ruby
|
637
519
|
youtube_transformer = lambda do |env|
|
638
|
-
node
|
520
|
+
node = env[:node]
|
639
521
|
node_name = env[:node_name]
|
640
522
|
|
641
523
|
# Don't continue if this node is already allowlisted or is not an element.
|
642
524
|
return if env[:is_allowlisted] || !node.element?
|
643
525
|
|
644
526
|
# Don't continue unless the node is an iframe.
|
645
|
-
return unless node_name ==
|
527
|
+
return unless node_name == "iframe"
|
646
528
|
|
647
529
|
# Verify that the video URL is actually a valid YouTube video URL.
|
648
|
-
return unless
|
530
|
+
return unless %r{\A(?:https?:)?//(?:www\.)?youtube(?:-nocookie)?\.com/}.match?(node["src"])
|
649
531
|
|
650
532
|
# We're now certain that this is a YouTube embed, but we still need to run
|
651
533
|
# it through a special Sanitize step to ensure that no unwanted elements or
|
652
534
|
# attributes that don't belong in a YouTube embed can sneak in.
|
653
535
|
Sanitize.node!(node, {
|
654
|
-
:
|
536
|
+
elements: %w[iframe],
|
655
537
|
|
656
|
-
:
|
657
|
-
|
538
|
+
attributes: {
|
539
|
+
"iframe" => %w[allowfullscreen frameborder height src width]
|
658
540
|
}
|
659
541
|
})
|
660
542
|
|
661
543
|
# Now that we're sure that this is a valid YouTube embed and that there are
|
662
544
|
# no unwanted elements or attributes hidden inside it, we can tell Sanitize
|
663
545
|
# to allowlist the current node.
|
664
|
-
{:
|
546
|
+
{node_allowlist: [node]}
|
665
547
|
end
|
666
548
|
|
667
549
|
html = %[
|
668
550
|
<iframe width="420" height="315" src="//www.youtube.com/embed/dQw4w9WgXcQ"
|
669
551
|
frameborder="0" allowfullscreen></iframe>
|
670
|
-
]
|
552
|
+
].strip
|
671
553
|
|
672
|
-
Sanitize.fragment(html, :
|
554
|
+
Sanitize.fragment(html, transformers: youtube_transformer)
|
673
555
|
# => '<iframe width="420" height="315" src="//www.youtube.com/embed/dQw4w9WgXcQ" frameborder="0" allowfullscreen=""></iframe>'
|
674
556
|
```
|