Same name and namespace in other branches
  1. 8.9.x core/lib/Drupal/Component/Utility/Xss.php \Drupal\Component\Utility\Xss::filter()
  2. 9 core/lib/Drupal/Component/Utility/Xss.php \Drupal\Component\Utility\Xss::filter()

Filters HTML to prevent cross-site-scripting (XSS) vulnerabilities.

Based on kses by Ulf Harnhammar, see http://sourceforge.net/projects/kses. For examples of various XSS attacks, see: http://ha.ckers.org/xss.html.

This code does four things:

  • Removes characters and constructs that can trick browsers.
  • Makes sure all HTML entities are well-formed.
  • Makes sure all HTML tags and attributes are well-formed.
  • Makes sure no HTML tags contain URLs with a disallowed protocol (e.g. javascript:).

Parameters

string $string: The string with raw HTML in it. It will be stripped of everything that can cause an XSS attack.

string[]|null $allowed_html_tags: An array of allowed HTML tags.

Return value

string An XSS safe version of $string, or an empty string if $string is not valid UTF-8.

See also

\Drupal\Component\Utility\Unicode::validateUtf8()

20 calls to Xss::filter()
AlterTest::testExecutionOrder in core/modules/system/tests/src/Functional/Form/AlterTest.php
Tests execution order of hook_form_alter() and hook_form_FORM_ID_alter().
AssertContentTrait::getTextContent in core/tests/Drupal/KernelTests/AssertContentTrait.php
Retrieves the plain-text content from the current raw content.
Error::formatBacktrace in core/lib/Drupal/Core/Utility/Error.php
Formats a backtrace into a plain-text string.
FieldCustomTest::testCustomFieldXss in core/modules/views/tests/src/Kernel/Handler/FieldCustomTest.php
Ensure that custom field content is XSS filtered.
FieldFilteredMarkup::create in core/lib/Drupal/Core/Field/FieldFilteredMarkup.php
Overrides \Drupal\Component\Render\MarkupTrait::create().

... See full list

File

core/lib/Drupal/Component/Utility/Xss.php, line 59

Class

Xss
Provides helper to filter for cross-site scripting.

Namespace

Drupal\Component\Utility

Code

public static function filter($string, array $allowed_html_tags = NULL) {
  if (is_null($allowed_html_tags)) {
    $allowed_html_tags = static::$htmlTags;
  }

  // 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 '';
  }

  // Remove NULL characters (ignored by some browsers).
  $string = str_replace(chr(0), '', $string);

  // Remove Netscape 4 JS entities.
  $string = preg_replace('%&\\s*\\{[^}]*(\\}\\s*;?|$)%', '', $string);

  // Defuse all HTML entities.
  $string = str_replace('&', '&', $string);

  // Change back only well-formed entities in our list of allowed html tags:
  // Decimal numeric entities.
  $string = preg_replace('/&#([0-9]+;)/', '&#\\1', $string);

  // Hexadecimal numeric entities.
  $string = preg_replace('/&#[Xx]0*((?:[0-9A-Fa-f]{2})+;)/', '&#x\\1', $string);

  // Named entities.
  $string = preg_replace('/&([A-Za-z][A-Za-z0-9]*;)/', '&\\1', $string);
  $allowed_html_tags = array_flip($allowed_html_tags);

  // Late static binding does not work inside anonymous functions.
  $class = static::class;
  $splitter = function ($matches) use ($allowed_html_tags, $class) {
    return $class::split($matches[1], $allowed_html_tags, $class);
  };

  // Strip any tags that are not in the list of allowed html tags.
  return preg_replace_callback('%
      (
      <(?=[^a-zA-Z!/])  # a lone <
      |                 # or
      <!--.*?-->        # a comment
      |                 # or
      <[^>]*(>|$)       # a string that starts with a <, up until the > or the end of the string
      |                 # or
      >                 # just a >
      )%x', $splitter, $string);
}