Basics
- PHP does not help, and sometimes causes problems
- Grant as little access as necessary
- Do not trust any input
Stay up to date

Never use PHP filter

Always use HTML filter

SQL injection
- Use Drupal's database API
db_query($query, …)
db_query_range($query, …, $form, $count)
pager_query($query, $limit, $element, $count_query, …)
SQL injection
'%s' string
%d digit
%f float
%n numeric
%b binary data
%% literal %
SQL injection
Lists:
db_placeholders($arguments, $type = 'int')
Working with text
- Plain text:
check_plain($text)
- HTML:
check_markup($text, $format)
- URL:
check_url($uri)
- Filter before sending to the theme
Working with text
t($string, $args)
% emphasized plain text
@ plain text
! no filtering
Working with text
- Basic:
filter_xss($string, $allowed_tags)
- Minimal:
filter_xss_admin($string)
Cross-site request forgery (CSRF)
- Targeted at users who do not notice attack
- Automates other attacks
- Implemented with URL hacks and Javascript
Cross-site request forgery (CSRF)
- Require POST for actions
- Use tokens
- Form API does all of this
Cross-site request forgery (CSRF)
Form API
- Checks for invalid selections
- Checks tokens
- Use submit handler:
{form}_submit($form, &$form_state)
Cross-site request forgery (CSRF)
For lightweight actions
- Construct URLs with
drupal_get_token($value)
- Validate with
drupal_valid_token($token, $value)
Access checks
hook_perm() {
return array('{permission name}', …);
}
user_access('{permission name}')
Menu access checks
$items['{path}'] = array(
'access callback' => '{function}',
'access arguments' => array({arguments}),
…
);
Node access checks
- Listings:
db_rewrite_sql($query)
- Single nodes:
node_access($op, $node)
Drupal Security Team
- Coordinates security releases
- Helps establish & promote best practices
Reporting or fixing a security issue
- Do NOT publicly post the issue.
- Do NOT commit the fix to CVS.
- Do email security@drupal.org
- Be as detailed & specific as possible