function Standard::filterXss

Same name and namespace in other branches
  1. 9 core/modules/editor/src/EditorXssFilter/Standard.php \Drupal\editor\EditorXssFilter\Standard::filterXss()
  2. 8.9.x core/modules/editor/src/EditorXssFilter/Standard.php \Drupal\editor\EditorXssFilter\Standard::filterXss()
  3. 10 core/modules/editor/src/EditorXssFilter/Standard.php \Drupal\editor\EditorXssFilter\Standard::filterXss()

Filters HTML to prevent XSS attacks when a user edits it in a text editor.

Should filter as minimally as possible, only to remove XSS attack vectors.

Is only called when:

  • loading a non-XSS-safe text editor for a $format that contains a filter preventing XSS attacks (a FilterInterface::TYPE_HTML_RESTRICTOR filter): if the output is safe, it should also be safe to edit.
  • loading a non-XSS-safe text editor for a $format that doesn't contain a filter preventing XSS attacks, but we're switching from a previous text format ($original_format is not NULL) that did prevent XSS attacks: if the output was previously safe, it should be safe to switch to another text format and edit.

Parameters

string $html: The HTML to be filtered.

\Drupal\filter\FilterFormatInterface $format: The text format configuration entity. Provides context based upon which one may want to adjust the filtering.

\Drupal\filter\FilterFormatInterface|null $original_format: (optional) The original text format configuration entity (when switching text formats/editors). Also provides context based upon which one may want to adjust the filtering.

Return value

string The filtered HTML that cannot cause any XSS anymore.

Overrides EditorXssFilterInterface::filterXss

2 calls to Standard::filterXss()
FilterKernelTest::testCaptionFilter in core/modules/filter/tests/src/Kernel/FilterKernelTest.php
Tests the caption filter.
StandardTest::testFilterXss in core/modules/editor/tests/src/Unit/EditorXssFilter/StandardTest.php
Tests the method for filtering XSS.

File

core/modules/editor/src/EditorXssFilter/Standard.php, line 18

Class

Standard
Defines the standard text editor XSS filter.

Namespace

Drupal\editor\EditorXssFilter

Code

public static function filterXss($html, FilterFormatInterface $format, ?FilterFormatInterface $original_format = NULL) {
  // Apply XSS filtering, but disallow the <script>, <style>, <link>, <embed>
  // and <object> tags.
  //
  // The <script> and <style> tags are removed because their contents can be
  // malicious (and therefore they are inherently unsafe), whereas for all
  // other tags, only their attributes can make them malicious. Since
  // \Drupal\Component\Utility\Xss::filter() is used to protect against
  // malicious attributes, we do not remove tags.
  //
  // The exceptions to the above rule are <link>, <embed> and <object>:
  // - <link> because the href attribute allows the attacker to import CSS
  //   using the HTTP(S) protocols which Xss::filter() considers safe by
  //   default. The imported remote CSS is applied to the main document, thus
  //   allowing for the same XSS attacks as a regular <style> tag.
  // - <embed> and <object> because these tags allow non-HTML applications or
  //   content to be embedded using the src or data attributes, respectively.
  //   This is safe in the case of HTML documents, but not in the case of
  //   Flash objects for example, that may access/modify the main document
  //   directly.
  // <iframe> is considered safe because it only allows HTML content to be
  // embedded, hence ensuring the same origin policy always applies.
  $dangerous_tags = [
    'script',
    'style',
    'link',
    'embed',
    'object',
  ];
  // Simply removing these five dangerous tags would bring safety, but also
  // user frustration: what if a text format is configured to allow <embed>,
  // for example? Then we would strip that tag, even though it is allowed,
  // thereby causing data loss!
  // Therefore, we want to be smarter still. We want to take into account
  // which HTML tags are allowed by the text format we're filtering for, and
  // if we're switching from another text format, we want to take that
  // format's allowed tags into account as well.
  // In other words: we only expect markup allowed in both the original and
  // the new format to continue to exist.
  $format_restrictions = $format->getHtmlRestrictions();
  if ($original_format !== NULL) {
    $original_format_restrictions = $original_format->getHtmlRestrictions();
  }
  // Any tags that are explicitly allowed by the text format must be removed
  // from the list of default dangerous tags: if they're explicitly allowed,
  // then we must respect that configuration.
  // When switching from another format, we must use the intersection of
  // allowed tags: if either format is more restrictive, then the safety
  // expectations of *both* formats apply.
  $allowed_tags = self::getAllowedTags($format_restrictions);
  if ($original_format !== NULL) {
    $allowed_tags = array_intersect($allowed_tags, self::getAllowedTags($original_format_restrictions));
  }
  // Don't remove dangerous tags that are explicitly allowed in both text
  // formats.
  $removed_tags = array_diff($dangerous_tags, $allowed_tags);
  $output = static::filter($html, $removed_tags);
  // Since data-attributes can contain encoded HTML markup that could be
  // decoded and interpreted by editors, we need to apply XSS filtering to
  // their contents.
  return static::filterXssDataAttributes($output);
}

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.