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

', Chris@0: 'onmouseover', Chris@0: 'HTML filter attributes removal -- events, no evasion.', Chris@0: ['p'], Chris@0: ], Chris@0: [ Chris@0: '

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

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

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