Last updated August 1, 2016. Created on May 7, 2006.
Edited by hansfn, DSquaredB, mlhess, pwolanin. Log in to edit this page.

Know about a security issue? Please alert the security team.

Whether you are writing a PHP snippet or an entire module, it is important to keep your code secure.

Use check functions on output to prevent cross site scripting attacks

No piece of user-submitted content should ever be placed as-is into HTML.

  • Use check_plain for plain text.
  • Use filter_xss for markup-containing text, or if the context is entered by an admin and should allow most markup, use filter_xss_admin. While it can also sanitize text, it's almost never correct to use check_markup in a theme or module except in the context of something like a text area with an associated text format.
  • Use the t() function with @ or % placeholders to construct safe, translatable strings.

See how to handle text in a secure fashion for more details.

Use the database abstraction layer to avoid SQL injection attacks

Use the database layer correctly. For example, never concatenate data directly into SQL queries, like this:

db_query('SELECT foo FROM {table} t WHERE t.name = '. $_GET['user']);

Instead, use proper argument substitution with db_query:

For Drupal 6 and before

db_query("SELECT foo FROM {table} t WHERE t.name = '%s' ", $_GET['user']);

If you have to accommodate a variable number of arguments in your SQL, create an array of placeholders. Do NOT do this:

db_query("SELECT t.s FROM {table} t WHERE t.field IN (%s)", $from_user);

Instead, do this:

$placeholders = implode(',', array_fill(0, count($from_user), "%d"));

db_query("SELECT t.s FROM {table} t WHERE t.field IN ($placeholders)", $from_user); 

For Drupal 7+

The DB layer works on top of PHP PDO and uses an array of named placholders:

db_query("SELECT foo FROM {table} t WHERE t.name = :name", array(':name' => $_GET['user']));

For a variable number of argument, use an array of arguments or use db_select():

db_query("SELECT t.s FROM {table} t WHERE t.field IN (:users)",  array(':users' => $from_user)); 

OR

$result = db_select('table', 't')
    ->fields('t', array('s'))
    ->condition('t.field', $from_user, 'IN')
    ->execute();

Use db_rewrite_sql to respect node access restrictions.

Most SQL statements which refer to nodes or the {node} table should be wrapped in a db_rewrite_sql() function call:

$result = db_query(db_rewrite_sql("SELECT n.nid, n.title FROM {node} n"));

Drupal's node access mechanism requires such calls. Without them, visitors may gain access to nodes that they don't have permission to view.

Looking for support? Visit the Drupal.org forums, or join #drupal-support in IRC.

Comments

crantok’s picture

I looked at the slideshare posted above. Slide #22 is a diagram showing when to use

  • check_url
  • check_plain
  • check_markup
  • filter_xss

That diagram did more in 1 second to explain when to use these functions than half an hour of reading handbook and api text. Could that slide be used either here (in the "Use check functions on output to prevent cross site scripting attacks" section), and/or on the Handle user input with care page?

mogulbuster’s picture

The IN clause example shown above that uses "implode" to create $placeholders will not work in Drupal 7; instead, you should do this:

<?php
   db_query("SELECT t.s FROM {table} t WHERE t.field IN (:ids)", array(':ids' => $from_user));
?>

See the "Placeholder arrays" section of http://drupal.org/node/310072 for details.

drilix’s picture

Instead of db_rewrite_sql on a db_query, it is advised, later in this book to use "db_select() tagged with (for example) 'node_access' in Drupal 7" https://www.drupal.org/node/93737

rhuffstedtler’s picture

See https://www.drupal.org/node/2549395#check_plain for recommended replacement strategies.