'regex', '#value' => '[\s\(]drupal_set_title\s*\(.*\$', '#never' => '(^function\s|drupal_set_title\s*\(\s*(((st|t|\$t)\s*\(.*?array\([^!]+\))|(format_plural|filter_xss_admin|check_plain|check_markup)\s*\().*$)', '#source' => 'allphp', '#warning_callback' => '_coder_review_security_drupal_set_title_filter_warning', ), array( '#type' => 'regex', '#value' => '[\s\(]drupal_set_message\s*\(.*\$', '#never' => '(^function\s|drupal_set_message\s*\(\s*(((st|t|\$t)\s*\(.*?array\([^!]+\))|(format_plural|filter_xss_admin|check_plain|check_markup)\s*\().*$)', '#source' => 'allphp', '#warning_callback' => '_coder_review_security_drupal_set_message_filter_warning', ), array( '#type' => 'regex', '#severity' => 'minor', '#value' => '[\s\(]l\(check_plain\(.*', '#never' => '[\'"]html[\'"]\s*=>\s*(TRUE|1)', '#source' => 'allphp', '#warning_callback' => '_coder_review_security_l_check_plain_warning', ), /* array( '#type' => 'callback', '#value' => _coder_review_security_callback, ), */ array( '#type' => 'regex', '#value' => '(?-i)\$REQUEST_URI', '#warning_callback' => '_coder_review_security_request_uri_warning', ), array( '#type' => 'regex', '#source' => 'allphp', '#value' => '(?-i)\"REQUEST_URI\"|\'REQUEST_URI\'', '#warning_callback' => '_coder_review_security_request_uri_warning', ), array( '#type' => 'regex', '#value' => '^(select\s+.*\s+from\s+' . $table . '|insert\s+into\s+' . $table . '|update\s+' . $table . '\s+set|delete\s+from\s+' . $table . ')\s+.*\$[a-z0-9_]+', '#not' => '\$placeholder', '#never' => '[\s\(]update_sql\(', '#source' => 'quote', '#warning_callback' => '_coder_review_security_sql_var_warning', ), array( '#type' => 'regex', '#value' => '^(select\s+.*\s+from\s+' . $table . '|insert\s+into\s+' . $table . '|update\s+' . $table . '\s+set|delete\s+from\s' . $table . ')\s+[^\']*?(\s+|\(|=|,)\%s', '#source' => 'quote', '#warning' => 'SQL query handling data in a potentially insecure way by using the %%s placeholder without wrapping it in single quotes. This is a potential source of SQL injection attacks when the value can come from user data.', ), array( '#type' => 'regex', '#source' => 'allphp', // allow us to look inside the regex string '#value' => '\bpreg_replace\s*\(\s*(\'(.)([^\'\\\\]|\\\\.)*\\2([^\'\\\\]|\\\\.)*|"(.)([^"\\\\]|\\\\.)*\\5([^"\\\\]|\\\\.)*)e', '#warning' => "Use preg_replace_callback() instead of the 'e' modifier to preg_replace()", '#severity' => 'critical', ), array( '#type' => 'regex', '#value' => '.*[\'"]SELECT\s+.*\s+(FROM|JOIN)\s+\{node\}', '#never' => '[\s\(]db_rewrite_sql\s*\(', '#source' => 'allphp', '#warning_callback' => '_coder_review_security_db_rewrite_sql', ), array( '#type' => 'regex', '#value' => '[\s\(]db_rewrite_sql\(\s*[\'"]SELECT\s+.*\s+(FROM|JOIN)\s+\{node\}([,\'"]+|\s+(ON|WHERE|HAVING|LIMIT|ORDER|GROUP)\s+)', '#never' => '[\s\(]db_rewrite_sql\(\s*[\'"]SELECT\s+.*\s+(FROM|JOIN)\s+\{node\}([,\'"]+|\s+(ON|WHERE|HAVING|LIMIT|ORDER|GROUP)\s+).*?,\s*[\'"]{node}[\'"]', '#source' => 'allphp', '#warning_callback' => '_coder_review_security_db_rewrite_sql', ), ); $review = array( '#title' => 'Drupal Security Checks', '#link' => 'http://drupal.org/node/28984', '#rules' => $rules, '#severity' => 'critical', '#description' => t('very basic, needs work, but what it finds is good'), ); return array('security' => $review); } /** * Define the rule callbacks. */ /* function _coder_review_security_callback(&$coder_args, $review, $rule, $lines, &$results) { if (!isset($coder_args['#tokens'])) { $source = implode('', $lines); $coder_args['#tokens'] = token_get_all($source); } } */ /** * Define the warning callbacks. */ function _coder_review_security_drupal_set_title_filter_warning() { return t('!drupal_set_title() only accepts filtered text, be sure to use !t(), !check_plain(), !filter_xss_admin() or similar.', array( '!drupal_set_title' => theme('drupalapi', 'drupal_set_title'), '!t' => theme('drupalapi', 't'), '!check_plain' => theme('drupalapi', 'check_plain'), '!filter_xss_admin' => theme('drupalapi', 'filter_xss_admin'), ) ); } function _coder_review_security_drupal_set_message_filter_warning() { return t('!drupal_set_message() only accepts filtered text, be sure to use !t(), !check_plain(), !filter_xss_admin() or similar.', array( '!drupal_set_message' => theme('drupalapi', 'drupal_set_message'), '!t' => theme('drupalapi', 't'), '!check_plain' => theme('drupalapi', 'check_plain'), '!filter_xss_admin' => theme('drupalapi', 'filter_xss_admin'), ) ); } function _coder_review_security_l_check_plain_warning() { return t('!l() already contains a !check_plain() call by default', array( '!l' => theme('drupalapi', array('function' => 'l')), '!check_plain' => theme('drupalapi', array('function' => 'check_plain')), ) ); } function _coder_review_security_request_uri_warning() { return t('the use of REQUEST_URI is prone to XSS exploits and does not work on IIS; use !request_uri() instead', array( '!request_uri' => theme('drupalapi', array('function' => 'request_uri')), ) ); } function _coder_review_security_sql_var_warning() { return array( '#warning' => t('In SQL strings, Use !db_query() placeholders in place of variables. This is a potential source of SQL injection attacks when the variable can come from user data.', array( '!db_query' => theme('drupalapi', array('function' => 'db_query')), ) ), '#link' => 'http://drupal.org/writing-secure-code', '#description' => t('Use %s and %d variable substitution. When inserting an array of values use $placeholders = implode(\',\', array_fill(0, count($args), "\'%s\'"));'), ); } function _coder_review_security_db_rewrite_sql() { return array( '#warning' => t('"SELECT FROM {node}" statements should probably be wrapped in !db_rewrite_sql and with the alias for {node} table defined (e.g. {node} n)', array( '!db_rewrite_sql' => theme('drupalapi', 'db_rewrite_sql'), ) ), ); }