4.6.x filter.module filter_xss($string, $allowed_tags = array('a', 'em', 'strong', 'cite', 'code', 'ul', 'ol', 'li', 'dl', 'dt', 'dd'))
4.7.x filter.module filter_xss($string, $allowed_tags = array('a', 'em', 'strong', 'cite', 'code', 'ul', 'ol', 'li', 'dl', 'dt', 'dd'))
5.x filter.module filter_xss($string, $allowed_tags = array('a', 'em', 'strong', 'cite', 'code', 'ul', 'ol', 'li', 'dl', 'dt', 'dd'))
6.x filter.module filter_xss($string, $allowed_tags = array('a', 'em', 'strong', 'cite', 'code', 'ul', 'ol', 'li', 'dl', 'dt', 'dd'))
7.x common.inc filter_xss($string, $allowed_tags = array('a', 'em', 'strong', 'cite', 'blockquote', 'code', 'ul', 'ol', 'li', 'dl', 'dt', 'dd'))

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: The string with raw HTML in it. It will be stripped of everything that can cause an XSS attack.

$allowed_tags: An array of allowed tags.

Return value

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

See also

drupal_validate_utf8()

Related topics

24 calls to filter_xss()
aggregator_filter_xss in modules/aggregator/aggregator.module
Renders the HTML content safely, as allowed.
CommentTokenReplaceTestCase::testCommentTokenReplacement in modules/comment/comment.test
Creates a comment, then tests the tokens generated from it.
comment_tokens in modules/comment/comment.tokens.inc
Implements hook_tokens().
CommonXssUnitTest::testInvalidMultiByte in modules/simpletest/tests/common.test
Check that invalid multi-byte sequences are rejected.
DBLogTestCase::assertLogMessage in modules/dblog/dblog.test
Confirms that a log message appears on the database log overview screen.

... See full list

2 string references to 'filter_xss'
_options_prepare_options in modules/field/modules/options/options.module
Sanitizes the options.
_options_properties in modules/field/modules/options/options.module
Describes the preparation steps required by each widget.

File

includes/common.inc, line 1473
Common functions that many Drupal modules will need to reference.

Code

function filter_xss($string, $allowed_tags = array('a', 'em', 'strong', 'cite', 'blockquote', 'code', 'ul', 'ol', 'li', 'dl', 'dt', 'dd')) {
  // Only operate on valid UTF-8 strings. This is necessary to prevent cross
  // site scripting issues on Internet Explorer 6.
  if (!drupal_validate_utf8($string)) {
    return '';
  }
  // Store the text format.
  _filter_xss_split($allowed_tags, TRUE);
  // 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 whitelist:
  // 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);

  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', '_filter_xss_split', $string);
}

Comments

Daniel Schaefer’s picture

Hi,
I understand the importance of the xss filtering. On one project we use the fieldset and legend element on Views. Currently I need to edit the common.inc on each update.

Would be possbile to include the fieldset and legend element by default? I don't think they would provide any danger as they only act as wrapper elements.

If not, can I add custom options using a hook?

Thanks

DetectivePixel’s picture

$my_allowed_tags = array('fieldset','legend');
filter_xss($some_string, $my_allowed_tags);
alex.designworks’s picture

Be aware that this will not be properly escaped and will trigger XSS warning:

Request:

http://www.example.com/node/123/%22onmouseover=%22alert(123)%22
or
http://www.example.com/node/123/"onmouseover="alert(123)"

In code:

<a href="http://www.example.com/node/567?<?php print filter_xss(current_path()); ?>"

The only way to escape is to use rawurlencode() or drupal_http_build_query().

Ayesh’s picture

This is a wrong use of filter_xss().
If you want to build a link, use l(). To build a URL, use url(). If you want to check a URL, use check_url(). Using filter_xss() in the middle of otherwise hostile HTML does not make it safe.

raghwendra’s picture

Just want to know how can we through warning in Drupal if some one using to put non allowed tag in filter. Thanks in advance!

kwfinken’s picture

Just compare the unfiltered string with the filtered and if they are not the same, issue your warning.