assertNormalized($value, $expected, $message); } /** * Data provider for testFilterXssNormalized(). * * @see testFilterXssNormalized() * * @return array * An array of arrays containing strings: * - The value to filter. * - The value to expect after filtering. * - The assertion message. * - (optional) The allowed HTML HTML tags array that should be passed to * \Drupal\Component\Utility\Xss::filter(). */ public function providerTestFilterXssNormalized() { return [ [ "Who's Online", "who's online", 'HTML filter -- html entity number', ], [ "Who&#039;s Online", "who's online", 'HTML filter -- encoded html entity number', ], [ "Who&amp;#039; Online", "who&#039; online", 'HTML filter -- double encoded html entity number', ], // Custom elements with dashes in the tag name. [ "", "", 'Custom element with dashes in tag name.', ['test-element'], ], ]; } /** * Tests limiting to allowed tags and XSS prevention. * * XSS tests assume that script is disallowed by default and src is allowed * by default, but on* and style attributes are disallowed. * * @param string $value * The value to filter. * @param string $expected * The string that is expected to be missing. * @param string $message * The assertion message to display upon failure. * @param array $allowed_tags * (optional) The allowed HTML tags to be passed to \Drupal\Component\Utility\Xss::filter(). * * @dataProvider providerTestFilterXssNotNormalized */ public function testFilterXssNotNormalized($value, $expected, $message, array $allowed_tags = NULL) { if ($allowed_tags === NULL) { $value = Xss::filter($value); } else { $value = Xss::filter($value, $allowed_tags); } $this->assertNotNormalized($value, $expected, $message); } /** * Data provider for testFilterXssNotNormalized(). * * @see testFilterXssNotNormalized() * * @return array * An array of arrays containing the following elements: * - The value to filter. * - The value to expect that's missing after filtering. * - The assertion message. * - (optional) The allowed HTML HTML tags array that should be passed to * \Drupal\Component\Utility\Xss::filter(). */ public function providerTestFilterXssNotNormalized() { $cases = [ // Tag stripping, different ways to work around removal of HTML tags. [ '', 'script', 'HTML tag stripping -- simple script without special characters.', ], [ '', 'script', 'HTML tag stripping evasion -- non whitespace character after tag name.', ], [ '', 'script', 'HTML tag stripping evasion -- no space between tag and attribute.', ], // Null between < and tag name works at least with IE6. [ "<\0scr\0ipt>alert(0)", 'ipt', 'HTML tag stripping evasion -- breaking HTML with nulls.', ], [ "", 'script', 'HTML tag stripping evasion -- filter just removing "script".', ], [ '<', 'script', 'HTML tag stripping evasion -- double opening brackets.', ], [ '', 'script', 'HTML tag stripping evasion -- a malformed image tag.', ['img'], ], [ '
', 'script', 'HTML tag stripping evasion -- script in a blockqoute.', ['blockquote'], ], [ "", 'script', 'HTML tag stripping evasion -- script within a comment.', ], // Dangerous attributes removal. [ '

', 'onmouseover', 'HTML filter attributes removal -- events, no evasion.', ['p'], ], [ '

  • ', 'style', 'HTML filter attributes removal -- style, no evasion.', ['li'], ], [ '', 'onerror', 'HTML filter attributes removal evasion -- spaces before equals sign.', ['img'], ], [ '', 'onabort', 'HTML filter attributes removal evasion -- non alphanumeric characters before equals sign.', ['img'], ], [ '', 'onmediaerror', 'HTML filter attributes removal evasion -- varying case.', ['img'], ], // Works at least with IE6. [ "", 'focus', 'HTML filter attributes removal evasion -- breaking with nulls.', ['img'], ], // Only whitelisted scheme names allowed in attributes. [ '', 'javascript', 'HTML scheme clearing -- no evasion.', ['img'], ], [ '', 'javascript', 'HTML scheme clearing evasion -- no quotes.', ['img'], ], // A bit like CVE-2006-0070. [ '', 'javascript', 'HTML scheme clearing evasion -- no alert ;)', ['img'], ], [ '', 'javascript', 'HTML scheme clearing evasion -- grave accents.', ['img'], ], [ '', 'javascript', 'HTML scheme clearing -- rare attribute.', ['img'], ], [ '', 'javascript', 'HTML scheme clearing -- another tag.', ['table'], ], [ '', 'javascript', 'HTML scheme clearing -- one more attribute and tag.', ['base'], ], [ '', 'javascript', 'HTML scheme clearing evasion -- varying case.', ['img'], ], [ '', 'javascript', 'HTML scheme clearing evasion -- UTF-8 decimal encoding.', ['img'], ], [ '', 'javascript', 'HTML scheme clearing evasion -- long UTF-8 encoding.', ['img'], ], [ '', 'javascript', 'HTML scheme clearing evasion -- UTF-8 hex encoding.', ['img'], ], [ "", 'script', 'HTML scheme clearing evasion -- an embedded tab.', ['img'], ], [ '', 'script', 'HTML scheme clearing evasion -- an encoded, embedded tab.', ['img'], ], [ '', 'script', 'HTML scheme clearing evasion -- an encoded, embedded newline.', ['img'], ], // With this test would fail, but the entity gets turned into // &#xD;, so it's OK. [ '', 'script', 'HTML scheme clearing evasion -- an encoded, embedded carriage return.', ['img'], ], [ "", 'cript', 'HTML scheme clearing evasion -- broken into many lines.', ['img'], ], [ "", 'cript', 'HTML scheme clearing evasion -- embedded nulls.', ['img'], ], [ '', 'vbscript', 'HTML scheme clearing evasion -- another scheme.', ['img'], ], [ '', 'nosuchscheme', 'HTML scheme clearing evasion -- unknown scheme.', ['img'], ], // Netscape 4.x javascript entities. [ '
    ', 'alert', 'Netscape 4.x javascript entities.', ['br'], ], // DRUPAL-SA-2008-006: Invalid UTF-8, these only work as reflected XSS with // Internet Explorer 6. [ "

    \" style=\"background-image: url(javascript:alert(0));\"\xe0

    ", 'style', 'HTML filter -- invalid UTF-8.', ['p'], ], ]; // @fixme This dataset currently fails under 5.4 because of // https://www.drupal.org/node/1210798. Restore after its fixed. if (version_compare(PHP_VERSION, '5.4.0', '<')) { $cases[] = [ '', 'javascript', 'HTML scheme clearing evasion -- spaces and metacharacters before scheme.', ['img'], ]; } return $cases; } /** * Checks that invalid multi-byte sequences are rejected. * * @param string $value * The value to filter. * @param string $expected * The expected result. * @param string $message * The assertion message to display upon failure. * * @dataProvider providerTestInvalidMultiByte */ public function testInvalidMultiByte($value, $expected, $message) { $this->assertEquals(Xss::filter($value), $expected, $message); } /** * Data provider for testInvalidMultiByte(). * * @see testInvalidMultiByte() * * @return array * An array of arrays containing strings: * - The value to filter. * - The value to expect after filtering. * - The assertion message. */ public function providerTestInvalidMultiByte() { return [ ["Foo\xC0barbaz", '', 'Xss::filter() accepted invalid sequence "Foo\xC0barbaz"'], ["Fooÿñ", "Fooÿñ", 'Xss::filter() rejects valid sequence Fooÿñ"'], ["\xc0aaa", '', 'HTML filter -- overlong UTF-8 sequences.'], ]; } /** * Checks that strings starting with a question sign are correctly processed. */ public function testQuestionSign() { $value = Xss::filter(''); $this->assertTrue(stripos($value, 'assertEquals($expected, $value, $message); } /** * Data provider for testFilterXssAdminNotNormalized(). */ public function providerTestAttributes() { return [ [ 'Example: alt', 'Example: alt', 'Image tag with alt and title attribute', ['img'] ], [ 'Drupal', 'Drupal', 'Link tag with rel attribute', ['a'] ], [ 'Drupal 8: The best release ever.', 'Drupal 8: The best release ever.', 'Span tag with property attribute', ['span'] ], [ '', '', 'Image tag with data attribute', ['img'] ], [ '', '', 'Link tag with numeric data attribute', ['a'] ], ]; } /** * Checks that \Drupal\Component\Utility\Xss::filterAdmin() correctly strips unallowed tags. */ public function testFilterXSSAdmin() { $value = Xss::filterAdmin('