diff --git a/core/modules/editor/src/EditorXssFilter/Standard.php b/core/modules/editor/src/EditorXssFilter/Standard.php index 310248d..63750aa 100644 --- a/core/modules/editor/src/EditorXssFilter/Standard.php +++ b/core/modules/editor/src/EditorXssFilter/Standard.php @@ -7,7 +7,11 @@ namespace Drupal\editor\EditorXssFilter; +use Drupal\Component\Utility\SafeMarkup; use Drupal\Component\Utility\Xss; +use Drupal\Component\Utility\Html; +use Drupal\Component\Utility\String; +use Drupal\Component\Utility\Unicode; use Drupal\filter\FilterFormatInterface; use Drupal\editor\EditorXssFilterInterface; @@ -85,7 +89,30 @@ public static function filterXss($html, FilterFormatInterface $format, FilterFor // Also blacklist tags that are explicitly forbidden in either text format. $blacklisted_tags = array_merge($blacklisted_tags, $forbidden_tags); - return static::filter($html, $blacklisted_tags); + $output = Xss::filter($html, $blacklisted_tags); + + // Since data-*-attributes can contain encoded markup that could be decoded + // and interpreted by editors, we need to apply XSS filtering to their + // contents. + return Standard::filterXssDataAttributes($output); + } + + /** + * Applies a very permissive XSS/HTML filter to data-attributes. + */ + protected static function filterXssDataAttributes($html) { + if (stristr($html, 'data-') !== FALSE) { + $dom = Html::load($html); + $xpath = new \DOMXPath($dom); + foreach ($xpath->query('//@*[starts-with(name(.), "data-")]') as $node) { + $value = String::decodeEntities($node->value); + $value = Xss::filterAdmin($value); + $node->value = SafeMarkup::checkPlain($value); + } + $html = Html::serialize($dom); + } + + return $html; } diff --git a/core/modules/filter/src/Plugin/Filter/FilterCaption.php b/core/modules/filter/src/Plugin/Filter/FilterCaption.php index 32977ec..b68e6d3 100644 --- a/core/modules/filter/src/Plugin/Filter/FilterCaption.php +++ b/core/modules/filter/src/Plugin/Filter/FilterCaption.php @@ -9,6 +9,7 @@ use Drupal\Component\Utility\Html; use Drupal\Component\Utility\SafeMarkup; +use Drupal\Component\Utility\String; use Drupal\Component\Utility\Unicode; use Drupal\Component\Utility\Xss; use Drupal\filter\FilterProcessResult; @@ -39,12 +40,12 @@ public function process($text, $langcode) { $xpath = new \DOMXPath($dom); foreach ($xpath->query('//*[@data-caption]') as $node) { // Read the data-caption attribute's value, then delete it. - $caption = SafeMarkup::checkPlain($node->getAttribute('data-caption')); + $caption = String::checkPlain($node->getAttribute('data-caption')); $node->removeAttribute('data-caption'); // Sanitize caption: decode HTML encoding, limit allowed HTML tags; only // allow inline tags that are allowed by default, plus
. - $caption = Html::decodeEntities($caption); + $caption = String::decodeEntities($caption); $caption = Xss::filter($caption, array('a', 'em', 'strong', 'cite', 'code', 'br')); // The caption must be non-empty. diff --git a/core/modules/filter/src/Tests/FilterUnitTest.php b/core/modules/filter/src/Tests/FilterUnitTest.php index a72a050..e25b2b4 100644 --- a/core/modules/filter/src/Tests/FilterUnitTest.php +++ b/core/modules/filter/src/Tests/FilterUnitTest.php @@ -10,6 +10,7 @@ use Drupal\Component\Utility\Html; use Drupal\Component\Utility\String; use Drupal\Component\Utility\Xss; +use Drupal\editor\EditorXssFilter\Standard; use Drupal\filter\FilterPluginCollection; use Drupal\simpletest\KernelTestBase; @@ -199,7 +200,7 @@ function testCaptionFilter() { // Editor XSS filter. $test_editor_xss_filter = function ($input) { $allowed_tags = array('img'); - return Xss::filter($input, $allowed_tags); + return Standard::filter($input, $allowed_tags); }; // All the tricky cases encountered at https://drupal.org/node/2105841. @@ -235,10 +236,10 @@ function testCaptionFilter() { $this->assertIdentical($expected, $test_with_html_filter($input)); $this->assertIdentical($input, $test_editor_xss_filter($input)); // An evil anchor (to ensure XSS filtering is applied to the caption also). - $input = ''; - $expected = '
This is an evil test…
'; + $input = ''; + $expected = '
This is an evil test…
'; $this->assertIdentical($expected, $test_with_html_filter($input)); - $expected_xss_filtered = ''; + $expected_xss_filtered = ''; $this->assertIdentical($expected_xss_filtered, $test_editor_xss_filter($input)); }