core/lib/Drupal/Component/Utility/Xss.php | 39 +++++++++++++------- core/modules/editor/js/editor.js | 12 +++--- .../editor/lib/Drupal/editor/EditorController.php | 2 +- .../lib/Drupal/editor/EditorXssFilter/Standard.php | 2 +- .../lib/Drupal/editor/EditorXssFilterInterface.php | 2 +- .../lib/Drupal/editor/Tests/EditorSecurityTest.php | 23 ++++++++++-- .../Tests/editor/EditorXssFilter/StandardTest.php | 2 +- .../Drupal/Tests/Component/Utility/XssTest.php | 10 ++--- 8 files changed, 58 insertions(+), 34 deletions(-) diff --git a/core/lib/Drupal/Component/Utility/Xss.php b/core/lib/Drupal/Component/Utility/Xss.php index 358bb62..ef35e2a 100644 --- a/core/lib/Drupal/Component/Utility/Xss.php +++ b/core/lib/Drupal/Component/Utility/Xss.php @@ -13,6 +13,18 @@ class Xss { /** + * Indicates that XSS filtering must be applied in whitelist mode: only + * specified HTML tags are allowed. + */ + const FILTER_MODE_WHITELIST = TRUE; + + /** + * Indicates that XSS filtering must be applied in blacklist mode: only + * specified HTML tags are disallowed. + */ + const FILTER_MODE_BLACKLIST = FALSE; + + /** * The list of html tags allowed by filterAdmin(). * * @var array @@ -39,10 +51,10 @@ class Xss { * can cause an XSS attack. * @param array $html_tags * An array of HTML tags. - * @param bool $whitelist - * (optional) Defaults to TRUE, so $html_tags is used as a whitelist of - * allowed tags. When set to FALSE, the list of HTML tags becomes a list of - * disallowed tags, i.e. a blacklist. + * @param bool $mode + * (optional) Defaults to FILTER_MODE_WHITELIST ($html_tags is used as a + * whitelist of allowed tags), but can also be set to FILTER_MODE_BLACKLIST + * ($html_tags is used as a blacklist of disallowed tags). * * @return string * An XSS safe version of $string, or an empty string if $string is not @@ -52,14 +64,14 @@ class Xss { * * @ingroup sanitization */ - public static function filter($string, $html_tags = array('a', 'em', 'strong', 'cite', 'blockquote', 'code', 'ul', 'ol', 'li', 'dl', 'dt', 'dd'), $whitelist = TRUE) { + public static function filter($string, $html_tags = array('a', 'em', 'strong', 'cite', 'blockquote', 'code', 'ul', 'ol', 'li', 'dl', 'dt', 'dd'), $mode = Xss::FILTER_MODE_WHITELIST) { // Only operate on valid UTF-8 strings. This is necessary to prevent cross // site scripting issues on Internet Explorer 6. if (!Unicode::validateUtf8($string)) { return ''; } // Store the text format. - static::split($html_tags, TRUE, $whitelist); + static::split($html_tags, TRUE, $mode); // Remove NULL characters (ignored by some browsers). $string = str_replace(chr(0), '', $string); // Remove Netscape 4 JS entities. @@ -117,20 +129,21 @@ public static function filterAdmin($string) { * If $store is FALSE then the array has one element, the HTML tag to process. * @param bool $store * Whether to store $matches. - * @param bool $whitelist + * @param bool $mode * (optional) Ignored when $store is FALSE, otherwise used to determine - * whether $matches is a list of allowed or disallowed HTML tags. + * whether $matches is a list of allowed (if FILTER_MODE_WHITELIST) or + * disallowed (if FILTER_MODE_BLACKLIST) HTML tags. * * @return string * If the element isn't allowed, an empty string. Otherwise, the cleaned up * version of the HTML element. */ - protected static function split($matches, $store = FALSE, $whitelist = TRUE) { - static $html_tags, $whitelist_mode; + protected static function split($matches, $store = FALSE, $mode = Xss::FILTER_MODE_WHITELIST) { + static $html_tags, $split_mode; if ($store) { $html_tags = array_flip($matches); - $whitelist_mode = $whitelist; + $split_mode = $mode; return; } @@ -160,11 +173,11 @@ protected static function split($matches, $store = FALSE, $whitelist = TRUE) { } // When in whitelist mode, an element is disallowed when not listed. - if ($whitelist_mode && !isset($html_tags[strtolower($elem)])) { + if ($split_mode === static::FILTER_MODE_WHITELIST && !isset($html_tags[strtolower($elem)])) { return ''; } // When in blacklist mode, an element is disallowed when listed. - elseif (!$whitelist_mode && isset($html_tags[strtolower($elem)])) { + elseif ($split_mode === static::FILTER_MODE_BLACKLIST && isset($html_tags[strtolower($elem)])) { return ''; } diff --git a/core/modules/editor/js/editor.js b/core/modules/editor/js/editor.js index 8061842..d6a828e 100644 --- a/core/modules/editor/js/editor.js +++ b/core/modules/editor/js/editor.js @@ -40,7 +40,7 @@ Drupal.behaviors.editor = { // because the user has the ability to switch to some text editor, other- // wise this code would not be executed. else { - $(field).on('change.editor keyup.editor', function () { + $(field).on('change.editor keypress.editor', function () { field.setAttribute('data-editor-value-is-changed', 'true'); // Just knowing that the value was changed is enough, stop tracking. $(field).off('.editor'); @@ -69,9 +69,7 @@ Drupal.behaviors.editor = { // Attach the new editor (if any). if (settings.editor.formats[activeFormatID]) { var format = settings.editor.formats[activeFormatID]; - filterXssWhenSwitching(field, format, originalFormatID, function () { - Drupal.editorAttach(field, format); - }); + filterXssWhenSwitching(field, format, originalFormatID, Drupal.editorAttach); } }); } @@ -179,7 +177,7 @@ Drupal.editorDetach = function (field, format, trigger) { function filterXssWhenSwitching (field, format, originalFormatID, callback) { // A text editor that already is XSS-safe needs no additional measures. if (format.editor.isXssSafe) { - callback(); + callback(field, format); } // Otherwise, ensure XSS safety: let the server XSS filter this value. else { @@ -188,7 +186,7 @@ function filterXssWhenSwitching (field, format, originalFormatID, callback) { type: 'POST', data: { 'value': field.value, - 'original_format': originalFormatID + 'original_format_id': originalFormatID }, dataType: 'json', success: function (xssFilteredValue) { @@ -196,7 +194,7 @@ function filterXssWhenSwitching (field, format, originalFormatID, callback) { if (xssFilteredValue !== false) { field.value = xssFilteredValue; } - callback(); + callback(field, format); } }); } diff --git a/core/modules/editor/lib/Drupal/editor/EditorController.php b/core/modules/editor/lib/Drupal/editor/EditorController.php index 6a9f34d..f68f2d4 100644 --- a/core/modules/editor/lib/Drupal/editor/EditorController.php +++ b/core/modules/editor/lib/Drupal/editor/EditorController.php @@ -72,7 +72,7 @@ public function filterXss(Request $request, FilterFormatInterface $filter_format } // The original_format parameter will only exist when switching text format. - $original_format_id = $request->request->get('original_format'); + $original_format_id = $request->request->get('original_format_id'); $original_format = NULL; if (isset($original_format_id)) { $original_format = $this->entityManager() diff --git a/core/modules/editor/lib/Drupal/editor/EditorXssFilter/Standard.php b/core/modules/editor/lib/Drupal/editor/EditorXssFilter/Standard.php index 3b07333..d632ccf 100644 --- a/core/modules/editor/lib/Drupal/editor/EditorXssFilter/Standard.php +++ b/core/modules/editor/lib/Drupal/editor/EditorXssFilter/Standard.php @@ -21,7 +21,7 @@ class Standard implements EditorXssFilterInterface { */ public static function filterXss($html, FilterFormatInterface $format, FilterFormatInterface $original_format = NULL) { // Apply XSS filtering, but only blacklist the