annotate core/tests/Drupal/Tests/Component/Utility/XssTest.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
Chris@0 1 <?php
Chris@0 2
Chris@0 3 namespace Drupal\Tests\Component\Utility;
Chris@0 4
Chris@0 5 use Drupal\Component\Utility\Html;
Chris@0 6 use Drupal\Component\Utility\UrlHelper;
Chris@0 7 use Drupal\Component\Utility\Xss;
Chris@0 8 use PHPUnit\Framework\TestCase;
Chris@0 9
Chris@0 10 /**
Chris@0 11 * XSS Filtering tests.
Chris@0 12 *
Chris@0 13 * @group Utility
Chris@0 14 *
Chris@0 15 * @coversDefaultClass \Drupal\Component\Utility\Xss
Chris@0 16 *
Chris@0 17 * Script injection vectors mostly adopted from http://ha.ckers.org/xss.html.
Chris@0 18 *
Chris@0 19 * Relevant CVEs:
Chris@0 20 * - CVE-2002-1806, ~CVE-2005-0682, ~CVE-2005-2106, CVE-2005-3973,
Chris@0 21 * CVE-2006-1226 (= rev. 1.112?), CVE-2008-0273, CVE-2008-3740.
Chris@0 22 */
Chris@0 23 class XssTest extends TestCase {
Chris@0 24
Chris@0 25 /**
Chris@0 26 * {@inheritdoc}
Chris@0 27 */
Chris@0 28 protected function setUp() {
Chris@0 29 parent::setUp();
Chris@0 30
Chris@0 31 $allowed_protocols = [
Chris@0 32 'http',
Chris@0 33 'https',
Chris@0 34 'ftp',
Chris@0 35 'news',
Chris@0 36 'nntp',
Chris@0 37 'telnet',
Chris@0 38 'mailto',
Chris@0 39 'irc',
Chris@0 40 'ssh',
Chris@0 41 'sftp',
Chris@0 42 'webcal',
Chris@0 43 'rtsp',
Chris@0 44 ];
Chris@0 45 UrlHelper::setAllowedProtocols($allowed_protocols);
Chris@0 46 }
Chris@0 47
Chris@0 48 /**
Chris@0 49 * Tests limiting allowed tags and XSS prevention.
Chris@0 50 *
Chris@0 51 * XSS tests assume that script is disallowed by default and src is allowed
Chris@0 52 * by default, but on* and style attributes are disallowed.
Chris@0 53 *
Chris@0 54 * @param string $value
Chris@0 55 * The value to filter.
Chris@0 56 * @param string $expected
Chris@0 57 * The expected result.
Chris@0 58 * @param string $message
Chris@0 59 * The assertion message to display upon failure.
Chris@0 60 * @param array $allowed_tags
Chris@0 61 * (optional) The allowed HTML tags to be passed to \Drupal\Component\Utility\Xss::filter().
Chris@0 62 *
Chris@0 63 * @dataProvider providerTestFilterXssNormalized
Chris@0 64 */
Chris@0 65 public function testFilterXssNormalized($value, $expected, $message, array $allowed_tags = NULL) {
Chris@0 66 if ($allowed_tags === NULL) {
Chris@0 67 $value = Xss::filter($value);
Chris@0 68 }
Chris@0 69 else {
Chris@0 70 $value = Xss::filter($value, $allowed_tags);
Chris@0 71 }
Chris@0 72 $this->assertNormalized($value, $expected, $message);
Chris@0 73 }
Chris@0 74
Chris@0 75 /**
Chris@0 76 * Data provider for testFilterXssNormalized().
Chris@0 77 *
Chris@0 78 * @see testFilterXssNormalized()
Chris@0 79 *
Chris@0 80 * @return array
Chris@0 81 * An array of arrays containing strings:
Chris@0 82 * - The value to filter.
Chris@0 83 * - The value to expect after filtering.
Chris@0 84 * - The assertion message.
Chris@0 85 * - (optional) The allowed HTML HTML tags array that should be passed to
Chris@0 86 * \Drupal\Component\Utility\Xss::filter().
Chris@0 87 */
Chris@0 88 public function providerTestFilterXssNormalized() {
Chris@0 89 return [
Chris@0 90 [
Chris@0 91 "Who&#039;s Online",
Chris@0 92 "who's online",
Chris@0 93 'HTML filter -- html entity number',
Chris@0 94 ],
Chris@0 95 [
Chris@0 96 "Who&amp;#039;s Online",
Chris@0 97 "who&#039;s online",
Chris@0 98 'HTML filter -- encoded html entity number',
Chris@0 99 ],
Chris@0 100 [
Chris@0 101 "Who&amp;amp;#039; Online",
Chris@0 102 "who&amp;#039; online",
Chris@0 103 'HTML filter -- double encoded html entity number',
Chris@0 104 ],
Chris@0 105 // Custom elements with dashes in the tag name.
Chris@0 106 [
Chris@0 107 "<test-element></test-element>",
Chris@0 108 "<test-element></test-element>",
Chris@0 109 'Custom element with dashes in tag name.',
Chris@0 110 ['test-element'],
Chris@0 111 ],
Chris@0 112 ];
Chris@0 113 }
Chris@0 114
Chris@0 115 /**
Chris@0 116 * Tests limiting to allowed tags and XSS prevention.
Chris@0 117 *
Chris@0 118 * XSS tests assume that script is disallowed by default and src is allowed
Chris@0 119 * by default, but on* and style attributes are disallowed.
Chris@0 120 *
Chris@0 121 * @param string $value
Chris@0 122 * The value to filter.
Chris@0 123 * @param string $expected
Chris@0 124 * The string that is expected to be missing.
Chris@0 125 * @param string $message
Chris@0 126 * The assertion message to display upon failure.
Chris@0 127 * @param array $allowed_tags
Chris@0 128 * (optional) The allowed HTML tags to be passed to \Drupal\Component\Utility\Xss::filter().
Chris@0 129 *
Chris@0 130 * @dataProvider providerTestFilterXssNotNormalized
Chris@0 131 */
Chris@0 132 public function testFilterXssNotNormalized($value, $expected, $message, array $allowed_tags = NULL) {
Chris@0 133 if ($allowed_tags === NULL) {
Chris@0 134 $value = Xss::filter($value);
Chris@0 135 }
Chris@0 136 else {
Chris@0 137 $value = Xss::filter($value, $allowed_tags);
Chris@0 138 }
Chris@0 139 $this->assertNotNormalized($value, $expected, $message);
Chris@0 140 }
Chris@0 141
Chris@0 142 /**
Chris@0 143 * Data provider for testFilterXssNotNormalized().
Chris@0 144 *
Chris@0 145 * @see testFilterXssNotNormalized()
Chris@0 146 *
Chris@0 147 * @return array
Chris@0 148 * An array of arrays containing the following elements:
Chris@0 149 * - The value to filter.
Chris@0 150 * - The value to expect that's missing after filtering.
Chris@0 151 * - The assertion message.
Chris@0 152 * - (optional) The allowed HTML HTML tags array that should be passed to
Chris@0 153 * \Drupal\Component\Utility\Xss::filter().
Chris@0 154 */
Chris@0 155 public function providerTestFilterXssNotNormalized() {
Chris@0 156 $cases = [
Chris@0 157 // Tag stripping, different ways to work around removal of HTML tags.
Chris@0 158 [
Chris@0 159 '<script>alert(0)</script>',
Chris@0 160 'script',
Chris@0 161 'HTML tag stripping -- simple script without special characters.',
Chris@0 162 ],
Chris@0 163 [
Chris@0 164 '<script src="http://www.example.com" />',
Chris@0 165 'script',
Chris@0 166 'HTML tag stripping -- empty script with source.',
Chris@0 167 ],
Chris@0 168 [
Chris@0 169 '<ScRipt sRc=http://www.example.com/>',
Chris@0 170 'script',
Chris@0 171 'HTML tag stripping evasion -- varying case.',
Chris@0 172 ],
Chris@0 173 [
Chris@0 174 "<script\nsrc\n=\nhttp://www.example.com/\n>",
Chris@0 175 'script',
Chris@0 176 'HTML tag stripping evasion -- multiline tag.',
Chris@0 177 ],
Chris@0 178 [
Chris@0 179 '<script/a src=http://www.example.com/a.js></script>',
Chris@0 180 'script',
Chris@0 181 'HTML tag stripping evasion -- non whitespace character after tag name.',
Chris@0 182 ],
Chris@0 183 [
Chris@0 184 '<script/src=http://www.example.com/a.js></script>',
Chris@0 185 'script',
Chris@0 186 'HTML tag stripping evasion -- no space between tag and attribute.',
Chris@0 187 ],
Chris@0 188 // Null between < and tag name works at least with IE6.
Chris@0 189 [
Chris@0 190 "<\0scr\0ipt>alert(0)</script>",
Chris@0 191 'ipt',
Chris@0 192 'HTML tag stripping evasion -- breaking HTML with nulls.',
Chris@0 193 ],
Chris@0 194 [
Chris@0 195 "<scrscriptipt src=http://www.example.com/a.js>",
Chris@0 196 'script',
Chris@0 197 'HTML tag stripping evasion -- filter just removing "script".',
Chris@0 198 ],
Chris@0 199 [
Chris@0 200 '<<script>alert(0);//<</script>',
Chris@0 201 'script',
Chris@0 202 'HTML tag stripping evasion -- double opening brackets.',
Chris@0 203 ],
Chris@0 204 [
Chris@0 205 '<script src=http://www.example.com/a.js?<b>',
Chris@0 206 'script',
Chris@0 207 'HTML tag stripping evasion -- no closing tag.',
Chris@0 208 ],
Chris@0 209 // DRUPAL-SA-2008-047: This doesn't seem exploitable, but the filter should
Chris@0 210 // work consistently.
Chris@0 211 [
Chris@0 212 '<script>>',
Chris@0 213 'script',
Chris@0 214 'HTML tag stripping evasion -- double closing tag.',
Chris@0 215 ],
Chris@0 216 [
Chris@0 217 '<script src=//www.example.com/.a>',
Chris@0 218 'script',
Chris@0 219 'HTML tag stripping evasion -- no scheme or ending slash.',
Chris@0 220 ],
Chris@0 221 [
Chris@0 222 '<script src=http://www.example.com/.a',
Chris@0 223 'script',
Chris@0 224 'HTML tag stripping evasion -- no closing bracket.',
Chris@0 225 ],
Chris@0 226 [
Chris@0 227 '<script src=http://www.example.com/ <',
Chris@0 228 'script',
Chris@0 229 'HTML tag stripping evasion -- opening instead of closing bracket.',
Chris@0 230 ],
Chris@0 231 [
Chris@0 232 '<nosuchtag attribute="newScriptInjectionVector">',
Chris@0 233 'nosuchtag',
Chris@0 234 'HTML tag stripping evasion -- unknown tag.',
Chris@0 235 ],
Chris@0 236 [
Chris@0 237 '<t:set attributeName="innerHTML" to="&lt;script defer&gt;alert(0)&lt;/script&gt;">',
Chris@0 238 't:set',
Chris@0 239 'HTML tag stripping evasion -- colon in the tag name (namespaces\' tricks).',
Chris@0 240 ],
Chris@0 241 [
Chris@0 242 '<img """><script>alert(0)</script>',
Chris@0 243 'script',
Chris@0 244 'HTML tag stripping evasion -- a malformed image tag.',
Chris@0 245 ['img'],
Chris@0 246 ],
Chris@0 247 [
Chris@0 248 '<blockquote><script>alert(0)</script></blockquote>',
Chris@0 249 'script',
Chris@0 250 'HTML tag stripping evasion -- script in a blockqoute.',
Chris@0 251 ['blockquote'],
Chris@0 252 ],
Chris@0 253 [
Chris@0 254 "<!--[if true]><script>alert(0)</script><![endif]-->",
Chris@0 255 'script',
Chris@0 256 'HTML tag stripping evasion -- script within a comment.',
Chris@0 257 ],
Chris@0 258 // Dangerous attributes removal.
Chris@0 259 [
Chris@0 260 '<p onmouseover="http://www.example.com/">',
Chris@0 261 'onmouseover',
Chris@0 262 'HTML filter attributes removal -- events, no evasion.',
Chris@0 263 ['p'],
Chris@0 264 ],
Chris@0 265 [
Chris@0 266 '<li style="list-style-image: url(javascript:alert(0))">',
Chris@0 267 'style',
Chris@0 268 'HTML filter attributes removal -- style, no evasion.',
Chris@0 269 ['li'],
Chris@0 270 ],
Chris@0 271 [
Chris@0 272 '<img onerror =alert(0)>',
Chris@0 273 'onerror',
Chris@0 274 'HTML filter attributes removal evasion -- spaces before equals sign.',
Chris@0 275 ['img'],
Chris@0 276 ],
Chris@0 277 [
Chris@0 278 '<img onabort!#$%&()*~+-_.,:;?@[/|\]^`=alert(0)>',
Chris@0 279 'onabort',
Chris@0 280 'HTML filter attributes removal evasion -- non alphanumeric characters before equals sign.',
Chris@0 281 ['img'],
Chris@0 282 ],
Chris@0 283 [
Chris@0 284 '<img oNmediAError=alert(0)>',
Chris@0 285 'onmediaerror',
Chris@0 286 'HTML filter attributes removal evasion -- varying case.',
Chris@0 287 ['img'],
Chris@0 288 ],
Chris@0 289 // Works at least with IE6.
Chris@0 290 [
Chris@0 291 "<img o\0nfocus\0=alert(0)>",
Chris@0 292 'focus',
Chris@0 293 'HTML filter attributes removal evasion -- breaking with nulls.',
Chris@0 294 ['img'],
Chris@0 295 ],
Chris@0 296 // Only whitelisted scheme names allowed in attributes.
Chris@0 297 [
Chris@0 298 '<img src="javascript:alert(0)">',
Chris@0 299 'javascript',
Chris@0 300 'HTML scheme clearing -- no evasion.',
Chris@0 301 ['img'],
Chris@0 302 ],
Chris@0 303 [
Chris@0 304 '<img src=javascript:alert(0)>',
Chris@0 305 'javascript',
Chris@0 306 'HTML scheme clearing evasion -- no quotes.',
Chris@0 307 ['img'],
Chris@0 308 ],
Chris@0 309 // A bit like CVE-2006-0070.
Chris@0 310 [
Chris@0 311 '<img src="javascript:confirm(0)">',
Chris@0 312 'javascript',
Chris@0 313 'HTML scheme clearing evasion -- no alert ;)',
Chris@0 314 ['img'],
Chris@0 315 ],
Chris@0 316 [
Chris@0 317 '<img src=`javascript:alert(0)`>',
Chris@0 318 'javascript',
Chris@0 319 'HTML scheme clearing evasion -- grave accents.',
Chris@0 320 ['img'],
Chris@0 321 ],
Chris@0 322 [
Chris@0 323 '<img dynsrc="javascript:alert(0)">',
Chris@0 324 'javascript',
Chris@0 325 'HTML scheme clearing -- rare attribute.',
Chris@0 326 ['img'],
Chris@0 327 ],
Chris@0 328 [
Chris@0 329 '<table background="javascript:alert(0)">',
Chris@0 330 'javascript',
Chris@0 331 'HTML scheme clearing -- another tag.',
Chris@0 332 ['table'],
Chris@0 333 ],
Chris@0 334 [
Chris@0 335 '<base href="javascript:alert(0);//">',
Chris@0 336 'javascript',
Chris@0 337 'HTML scheme clearing -- one more attribute and tag.',
Chris@0 338 ['base'],
Chris@0 339 ],
Chris@0 340 [
Chris@0 341 '<img src="jaVaSCriPt:alert(0)">',
Chris@0 342 'javascript',
Chris@0 343 'HTML scheme clearing evasion -- varying case.',
Chris@0 344 ['img'],
Chris@0 345 ],
Chris@0 346 [
Chris@0 347 '<img src=&#106;&#97;&#118;&#97;&#115;&#99;&#114;&#105;&#112;&#116;&#58;&#97;&#108;&#101;&#114;&#116;&#40;&#48;&#41;>',
Chris@0 348 'javascript',
Chris@0 349 'HTML scheme clearing evasion -- UTF-8 decimal encoding.',
Chris@0 350 ['img'],
Chris@0 351 ],
Chris@0 352 [
Chris@0 353 '<img src=&#00000106&#0000097&#00000118&#0000097&#00000115&#0000099&#00000114&#00000105&#00000112&#00000116&#0000058&#0000097&#00000108&#00000101&#00000114&#00000116&#0000040&#0000048&#0000041>',
Chris@0 354 'javascript',
Chris@0 355 'HTML scheme clearing evasion -- long UTF-8 encoding.',
Chris@0 356 ['img'],
Chris@0 357 ],
Chris@0 358 [
Chris@0 359 '<img src=&#x6A&#x61&#x76&#x61&#x73&#x63&#x72&#x69&#x70&#x74&#x3A&#x61&#x6C&#x65&#x72&#x74&#x28&#x30&#x29>',
Chris@0 360 'javascript',
Chris@0 361 'HTML scheme clearing evasion -- UTF-8 hex encoding.',
Chris@0 362 ['img'],
Chris@0 363 ],
Chris@0 364 [
Chris@0 365 "<img src=\"jav\tascript:alert(0)\">",
Chris@0 366 'script',
Chris@0 367 'HTML scheme clearing evasion -- an embedded tab.',
Chris@0 368 ['img'],
Chris@0 369 ],
Chris@0 370 [
Chris@0 371 '<img src="jav&#x09;ascript:alert(0)">',
Chris@0 372 'script',
Chris@0 373 'HTML scheme clearing evasion -- an encoded, embedded tab.',
Chris@0 374 ['img'],
Chris@0 375 ],
Chris@0 376 [
Chris@0 377 '<img src="jav&#x000000A;ascript:alert(0)">',
Chris@0 378 'script',
Chris@0 379 'HTML scheme clearing evasion -- an encoded, embedded newline.',
Chris@0 380 ['img'],
Chris@0 381 ],
Chris@0 382 // With &#xD; this test would fail, but the entity gets turned into
Chris@0 383 // &amp;#xD;, so it's OK.
Chris@0 384 [
Chris@0 385 '<img src="jav&#x0D;ascript:alert(0)">',
Chris@0 386 'script',
Chris@0 387 'HTML scheme clearing evasion -- an encoded, embedded carriage return.',
Chris@0 388 ['img'],
Chris@0 389 ],
Chris@0 390 [
Chris@0 391 "<img src=\"\n\n\nj\na\nva\ns\ncript:alert(0)\">",
Chris@0 392 'cript',
Chris@0 393 'HTML scheme clearing evasion -- broken into many lines.',
Chris@0 394 ['img'],
Chris@0 395 ],
Chris@0 396 [
Chris@0 397 "<img src=\"jav\0a\0\0cript:alert(0)\">",
Chris@0 398 'cript',
Chris@0 399 'HTML scheme clearing evasion -- embedded nulls.',
Chris@0 400 ['img'],
Chris@0 401 ],
Chris@0 402 [
Chris@0 403 '<img src="vbscript:msgbox(0)">',
Chris@0 404 'vbscript',
Chris@0 405 'HTML scheme clearing evasion -- another scheme.',
Chris@0 406 ['img'],
Chris@0 407 ],
Chris@0 408 [
Chris@0 409 '<img src="nosuchscheme:notice(0)">',
Chris@0 410 'nosuchscheme',
Chris@0 411 'HTML scheme clearing evasion -- unknown scheme.',
Chris@0 412 ['img'],
Chris@0 413 ],
Chris@0 414 // Netscape 4.x javascript entities.
Chris@0 415 [
Chris@0 416 '<br size="&{alert(0)}">',
Chris@0 417 'alert',
Chris@0 418 'Netscape 4.x javascript entities.',
Chris@0 419 ['br'],
Chris@0 420 ],
Chris@0 421 // DRUPAL-SA-2008-006: Invalid UTF-8, these only work as reflected XSS with
Chris@0 422 // Internet Explorer 6.
Chris@0 423 [
Chris@0 424 "<p arg=\"\xe0\">\" style=\"background-image: url(javascript:alert(0));\"\xe0<p>",
Chris@0 425 'style',
Chris@0 426 'HTML filter -- invalid UTF-8.',
Chris@0 427 ['p'],
Chris@0 428 ],
Chris@0 429 ];
Chris@0 430 // @fixme This dataset currently fails under 5.4 because of
Chris@0 431 // https://www.drupal.org/node/1210798. Restore after its fixed.
Chris@0 432 if (version_compare(PHP_VERSION, '5.4.0', '<')) {
Chris@0 433 $cases[] = [
Chris@0 434 '<img src=" &#14; javascript:alert(0)">',
Chris@0 435 'javascript',
Chris@0 436 'HTML scheme clearing evasion -- spaces and metacharacters before scheme.',
Chris@0 437 ['img'],
Chris@0 438 ];
Chris@0 439 }
Chris@0 440 return $cases;
Chris@0 441 }
Chris@0 442
Chris@0 443 /**
Chris@0 444 * Checks that invalid multi-byte sequences are rejected.
Chris@0 445 *
Chris@0 446 * @param string $value
Chris@0 447 * The value to filter.
Chris@0 448 * @param string $expected
Chris@0 449 * The expected result.
Chris@0 450 * @param string $message
Chris@0 451 * The assertion message to display upon failure.
Chris@0 452 *
Chris@0 453 * @dataProvider providerTestInvalidMultiByte
Chris@0 454 */
Chris@0 455 public function testInvalidMultiByte($value, $expected, $message) {
Chris@0 456 $this->assertEquals(Xss::filter($value), $expected, $message);
Chris@0 457 }
Chris@0 458
Chris@0 459 /**
Chris@0 460 * Data provider for testInvalidMultiByte().
Chris@0 461 *
Chris@0 462 * @see testInvalidMultiByte()
Chris@0 463 *
Chris@0 464 * @return array
Chris@0 465 * An array of arrays containing strings:
Chris@0 466 * - The value to filter.
Chris@0 467 * - The value to expect after filtering.
Chris@0 468 * - The assertion message.
Chris@0 469 */
Chris@0 470 public function providerTestInvalidMultiByte() {
Chris@0 471 return [
Chris@0 472 ["Foo\xC0barbaz", '', 'Xss::filter() accepted invalid sequence "Foo\xC0barbaz"'],
Chris@0 473 ["Fooÿñ", "Fooÿñ", 'Xss::filter() rejects valid sequence Fooÿñ"'],
Chris@0 474 ["\xc0aaa", '', 'HTML filter -- overlong UTF-8 sequences.'],
Chris@0 475 ];
Chris@0 476 }
Chris@0 477
Chris@0 478 /**
Chris@0 479 * Checks that strings starting with a question sign are correctly processed.
Chris@0 480 */
Chris@0 481 public function testQuestionSign() {
Chris@0 482 $value = Xss::filter('<?xml:namespace ns="urn:schemas-microsoft-com:time">');
Chris@0 483 $this->assertTrue(stripos($value, '<?xml') === FALSE, 'HTML tag stripping evasion -- starting with a question sign (processing instructions).');
Chris@0 484 }
Chris@0 485
Chris@0 486 /**
Chris@0 487 * Check that strings in HTML attributes are correctly processed.
Chris@0 488 *
Chris@0 489 * @covers ::attributes
Chris@0 490 * @dataProvider providerTestAttributes
Chris@0 491 */
Chris@0 492 public function testAttribute($value, $expected, $message, $allowed_tags = NULL) {
Chris@0 493 $value = Xss::filter($value, $allowed_tags);
Chris@0 494 $this->assertEquals($expected, $value, $message);
Chris@0 495 }
Chris@0 496
Chris@0 497 /**
Chris@0 498 * Data provider for testFilterXssAdminNotNormalized().
Chris@0 499 */
Chris@0 500 public function providerTestAttributes() {
Chris@0 501 return [
Chris@0 502 [
Chris@0 503 '<img src="http://example.com/foo.jpg" title="Example: title" alt="Example: alt">',
Chris@0 504 '<img src="http://example.com/foo.jpg" title="Example: title" alt="Example: alt">',
Chris@0 505 'Image tag with alt and title attribute',
Chris@17 506 ['img'],
Chris@0 507 ],
Chris@0 508 [
Chris@0 509 '<a href="https://www.drupal.org/" rel="dc:publisher">Drupal</a>',
Chris@0 510 '<a href="https://www.drupal.org/" rel="dc:publisher">Drupal</a>',
Chris@0 511 'Link tag with rel attribute',
Chris@17 512 ['a'],
Chris@0 513 ],
Chris@0 514 [
Chris@0 515 '<span property="dc:subject">Drupal 8: The best release ever.</span>',
Chris@0 516 '<span property="dc:subject">Drupal 8: The best release ever.</span>',
Chris@0 517 'Span tag with property attribute',
Chris@17 518 ['span'],
Chris@0 519 ],
Chris@0 520 [
Chris@0 521 '<img src="http://example.com/foo.jpg" data-caption="Drupal 8: The best release ever.">',
Chris@0 522 '<img src="http://example.com/foo.jpg" data-caption="Drupal 8: The best release ever.">',
Chris@0 523 'Image tag with data attribute',
Chris@17 524 ['img'],
Chris@0 525 ],
Chris@0 526 [
Chris@0 527 '<a data-a2a-url="foo"></a>',
Chris@0 528 '<a data-a2a-url="foo"></a>',
Chris@0 529 'Link tag with numeric data attribute',
Chris@17 530 ['a'],
Chris@0 531 ],
Chris@0 532 ];
Chris@0 533 }
Chris@0 534
Chris@0 535 /**
Chris@0 536 * Checks that \Drupal\Component\Utility\Xss::filterAdmin() correctly strips unallowed tags.
Chris@0 537 */
Chris@0 538 public function testFilterXSSAdmin() {
Chris@0 539 $value = Xss::filterAdmin('<style /><iframe /><frame /><frameset /><meta /><link /><embed /><applet /><param /><layer />');
Chris@0 540 $this->assertEquals($value, '', 'Admin HTML filter -- should never allow some tags.');
Chris@0 541 }
Chris@0 542
Chris@0 543 /**
Chris@0 544 * Tests the loose, admin HTML filter.
Chris@0 545 *
Chris@0 546 * @param string $value
Chris@0 547 * The value to filter.
Chris@0 548 * @param string $expected
Chris@0 549 * The expected result.
Chris@0 550 * @param string $message
Chris@0 551 * The assertion message to display upon failure.
Chris@0 552 *
Chris@0 553 * @dataProvider providerTestFilterXssAdminNotNormalized
Chris@0 554 */
Chris@0 555 public function testFilterXssAdminNotNormalized($value, $expected, $message) {
Chris@0 556 $this->assertNotNormalized(Xss::filterAdmin($value), $expected, $message);
Chris@0 557 }
Chris@0 558
Chris@0 559 /**
Chris@0 560 * Data provider for testFilterXssAdminNotNormalized().
Chris@0 561 *
Chris@0 562 * @see testFilterXssAdminNotNormalized()
Chris@0 563 *
Chris@0 564 * @return array
Chris@0 565 * An array of arrays containing strings:
Chris@0 566 * - The value to filter.
Chris@0 567 * - The value to expect after filtering.
Chris@0 568 * - The assertion message.
Chris@0 569 */
Chris@0 570 public function providerTestFilterXssAdminNotNormalized() {
Chris@0 571 return [
Chris@0 572 // DRUPAL-SA-2008-044
Chris@0 573 ['<object />', 'object', 'Admin HTML filter -- should not allow object tag.'],
Chris@0 574 ['<script />', 'script', 'Admin HTML filter -- should not allow script tag.'],
Chris@0 575 ];
Chris@0 576 }
Chris@0 577
Chris@0 578 /**
Chris@0 579 * Asserts that a text transformed to lowercase with HTML entities decoded does contain a given string.
Chris@0 580 *
Chris@0 581 * Otherwise fails the test with a given message, similar to all the
Chris@0 582 * SimpleTest assert* functions.
Chris@0 583 *
Chris@0 584 * Note that this does not remove nulls, new lines and other characters that
Chris@0 585 * could be used to obscure a tag or an attribute name.
Chris@0 586 *
Chris@0 587 * @param string $haystack
Chris@0 588 * Text to look in.
Chris@0 589 * @param string $needle
Chris@0 590 * Lowercase, plain text to look for.
Chris@0 591 * @param string $message
Chris@0 592 * (optional) Message to display if failed. Defaults to an empty string.
Chris@0 593 * @param string $group
Chris@0 594 * (optional) The group this message belongs to. Defaults to 'Other'.
Chris@0 595 */
Chris@0 596 protected function assertNormalized($haystack, $needle, $message = '', $group = 'Other') {
Chris@0 597 $this->assertTrue(strpos(strtolower(Html::decodeEntities($haystack)), $needle) !== FALSE, $message, $group);
Chris@0 598 }
Chris@0 599
Chris@0 600 /**
Chris@0 601 * Asserts that text transformed to lowercase with HTML entities decoded does not contain a given string.
Chris@0 602 *
Chris@0 603 * Otherwise fails the test with a given message, similar to all the
Chris@0 604 * SimpleTest assert* functions.
Chris@0 605 *
Chris@0 606 * Note that this does not remove nulls, new lines, and other character that
Chris@0 607 * could be used to obscure a tag or an attribute name.
Chris@0 608 *
Chris@0 609 * @param string $haystack
Chris@0 610 * Text to look in.
Chris@0 611 * @param string $needle
Chris@0 612 * Lowercase, plain text to look for.
Chris@0 613 * @param string $message
Chris@0 614 * (optional) Message to display if failed. Defaults to an empty string.
Chris@0 615 * @param string $group
Chris@0 616 * (optional) The group this message belongs to. Defaults to 'Other'.
Chris@0 617 */
Chris@0 618 protected function assertNotNormalized($haystack, $needle, $message = '', $group = 'Other') {
Chris@0 619 $this->assertTrue(strpos(strtolower(Html::decodeEntities($haystack)), $needle) === FALSE, $message, $group);
Chris@0 620 }
Chris@0 621
Chris@0 622 }