跳转到主要内容
木棉 提交于 8 February 2013

原文链接:http://drupal.org/node/101496

  Drupal提供了几个函数发送数据库查询。标准的形式是db_query。使用Drupal提供的函数进行数据库存取防止SQL注入。然而,仅仅使用函数是不足的见下面的例子说明:
<?php

/** Example 1 - Insecure

  * SQL injection via $type

  * Display node titles of type $type (input supplied by the user via a form textfield)

  */

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


$items = array();

while ($row = db_fetch_object($result)) {

  $items[] = l($row->title, "node/{$row->nid}");

}

return theme('item_list', $items);

?>

示例1显示了一个根据用户提供的参数类型的标题列表。当$type是一个page时一个页面的结点将被检索,当$type是story时是一个story结点列表。不幸的是,这个例子是很容易受SQL攻击注入的。该漏洞可以被用在数据库与UMION支持(MySQL 4.1+)获得管理员通过提供的类型访问站点:story' UNION SELECT s.sid, s.sid FROM {sessions} s WHERE s.uid = 1/*。
这将导致执行以下查询:
SELECT n.nid, n.title FROM {node} n WHERE n.type = 'story' UNION SELECT s.sid, s.sid FROM {sessions} s WHERE s.uid = 1/*'
作为片段将为管理员用户账户显示有效的会话id,攻击者可以指导他或她的浏览器使用id和充分的权限在网站上。

参数化查询防止SQL注入

防止SQL注入很容易;db_query提供的一种方式参数化查询。Drupal数据库函数代替 sprintf-like占位符正确转义参数出现的顺序。
<?php

db_query("SELECT n.nid FROM {node} n WHERE n.nid > %d", $nid);

db_query("SELECT n.nid FROM {node} n WHERE n.type = '%s'", $type);

db_query("SELECT n.nid FROM {node} n WHERE n.nid > %d AND n.type = '%s'", $nid, $type);

db_query("SELECT n.nid FROM {node} n WHERE n.type = '%s' AND n.nid > %d", $type, $nid);

?>
API documentation中有效的占位符:
  • %d - integers
  • %f - floats
  • %s - strings, enclose in ''
  • %b - binary data, do not enclose in ''
  • %% - replaced with %
正确的示例1:
<?php

/** Example 1 - Corrected

  * Display node titles of type $type (input supplied by the user via a form textfield)

  */

$result = db_query("SELECT n.nid, n.title FROM {node} n WHERE n.type = '%s'", $type);


$items = array();

while ($row = db_fetch_object($result)) {

  $items[] = l($row->title, "node/{$row->nid}");

}

return theme('item_list', $items);

?>

多参数

有时候你需要注入多参数的查询,使用IN()函数。 Drupal5中你应该使用这样的代码:
<?php

// Prepare $placeholders to be, e.g., "%d, %d, %d, %d, %d"

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


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

?>
Drupal6提供了db_placeholders。例如:
<?php

$values = array(1, 2, 3, 4, 5);


$placeholders = db_placeholders($values);


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

?>
对于Drupal7,见 Database API documentation