Drupal Security - User Input - Part II

This post we'll be talking about Cross Site Scripting or XSS and what steps to take to prevent this type of security breach on your Drupal site. Without going into the gory details, XSS allows a malicious user to insert a script into one of your web pages, that can be used to steal other user's identities, craft phishing attacks, and bypass access controls. For more detailed examples of XSS attacks see: http://ha.ckers.org/xss.html.

In my last post I wrote about the check_plain() function. It's the most restrictive of Drupal's filter functions. But suppose you want to loosen up on the reins a bit and allow your users to include some markup in their post. How do we do that without your site becoming the other www (wild wild west) where anything goes? The answer, partner, is to gather up yer posse... just kidding... use the filter_xss() function. Alright, I promise to quit with the corny cowboy references.

Remember, Drupal stores user input in its original form, so after it is retrieved from the database, it must be filtered before it is rendered on one of your pages. As an example, let's say you want to add the user's signature data at the bottom of any nodes they have written. You want them to be able to include a link to their home page, list their favorite John Wayne movies, and emphasize in bold their favorite Will Rogers song. Thinking about the type of information that can be displayed is critical. In this example we have <a>, <ol>, <ul>, <li>, <em>, and <strong> to cover our use cases. The function definition for filter_xss is as follows:

function filter_xss($string, $allowed_tags = array('a', 'em', 'strong', 'cite', 'code', 'ul', 'ol', 'li', 'dl', 'dt', 'dd'))

$string is the user data to be filtered and $allowed_tags, aptly named, are the markup tags that the user is allowed to use in their signature. Continuing our example, look at the following code snippet:

function your_module_nodeapi(&$node, $op, $a3 = NULL, $a4 = NULL) {
  switch ($op) {
    case 'view':
      $signature = db_result(db_query("SELECT signature FROM {users}
        WHERE uid = %d", $node->uid);
      $node->content['signature'] = array(
        '#value' => '<p>'. filter_xss($signature,
          array('a', 'ol', 'ul', 'li', 'em', 'strong') .'</p>',
        '#weight' => 10,
      );
      break;
  }
}

We are using hook_nodeapi to insert the user's signature into the $node->content array. Before adding the data we daftly pass it through filter_xss with our carefully thought out array of permissible html tags. That's it! No need sleeping with one eye open and yer gun under yer pillow. I know, I'm a terrible dork!

Next time we'll talk about the check_markup() function.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • E-Mail addresses are hidden with reCAPTCHA Mailhide.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Allowed HTML tags: <a> <em> <strong> <cite> <code> <ul> <ol> <li> <dl> <dt> <dd>
  • Lines and paragraphs break automatically.
  • You may post code using <code>...</code> (generic) or <?php ... ?> (highlighted PHP) tags.

More information about formatting options

CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.