php - Pdo prepare的语句是否足以防御sql注入?

假设我有这样的代码:


$dbh = new PDO("blahblah");

$stmt = $dbh->prepare('SELECT * FROM users where username = :username');
$stmt->execute( array(':username' => $_REQUEST['username']) );

真的就可以避免SQL注入吗?

时间:

准备好的语句/参数化查询足以防止该语句上的一阶注入。 如果你在应用程序的其他地方使用un-checked动态 sql,那么你仍然会受到 ii 注入的攻击。

二阶注入手段之前被包括在查询中的数据已经进行遍历一次数据库,和就更难拔掉电源插头。 AFAIK,你几乎不会看到真正的2和顺序攻击,因为攻击者通常更容易 social-engineer 。

当你可以使一个值存储在以后用作查询中的文本的数据库中时,你可以完成 2 nd顺序注入攻击。 例如假设在网站( 假设这个问题的MySQL DB ) 上创建帐户时,你将以下信息作为新用户名输入:


' + (SELECT UserName + '_' + Password FROM Users LIMIT 1) + '

如果用户名没有其他限制,准备好的语句仍然会确保上面的嵌入查询在插入时不会执行,并在数据库中正确存储该值。 但是,假设应用程序稍后从数据库中检索你的用户名,并使用字符串连接来包含一个新的查询。 你可能会看到别人的密码。 因为用户表中的前几个名字往往是管理员,你也可能刚刚给出了场。 ( 也注意:这是不将密码存储在纯文本中的另一个原因) !

我们看到,那么,预处理语句是讲到这一个单一的查询,但是通过本身,它们不是 足以抵御 SQL注入 攻击要在整个应用程序中,所有对数据库的访问,因为他们缺乏一种机制来强制该应用程序使用安全的代码内。 于求解 SQL注入 相关problem,但是,作为优秀的应用程序设计的一部分使用—这可能会包括实践,比如代码检查或者使用的一个 ORM,数据层或者服务层,用来限制动态 sql — 预处理语句 的是主 tool. 如果遵循良好的应用程序设计原则,使数据访问与程序的其余部分分离,就可以轻松实施或者审计每个查询都使用参数化。 在这种情况下,SQL注入 ( 第一个和第二个顺序) 被完全阻止。

不,并非总是如此。

这取决于是否允许在查询中放置用户输入,例如:


$dbh = new PDO("blahblah");

$tableToUse = $_GET['userTable'];

$stmt = $dbh->prepare('SELECT * FROM ' . $tableToUse . ' where username = :username');
$stmt->execute( array(':username' => $_REQUEST['username']) );

正确的答案是使用某种过滤/验证,例如:


$dbh = new PDO("blahblah");

$tableToUse = $_GET['userTable'];
$allowedTables = array('users','admins','moderators');
if (!in_array($tableToUse,$allowedTables)) 
 $tableToUse = 'users';

$stmt = $dbh->prepare('SELECT * FROM ' . $tableToUse . ' where username = :username');
$stmt->execute( array(':username' => $_REQUEST['username']) );

注:不能使用PDO绑定DDL (数据定义语言)之外的数据,换句话说,这不能工作:


$stmt = $dbh->prepare('SELECT * FROM foo ORDER BY :userSuppliedData');

不,这还不够(在某些特定情况下)!缺省情况下,当使用MySQL作为数据库驱动程序时,PDO使用模拟的准备语句,在使用MySQL和PDO时,应该始终禁用模拟的prepared语句:


$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);

总是应该做它设置正确的数据库编码:


$dbh = new PDO('mysql:dbname=dbtest;host=127.0.0.1;charset=utf8', 'user', 'pass');

另请参阅以下相关问题:防止SQL注入在PHP中的最佳方法

例如,使用htmlspecialchars()和正确的编码和引用样式。

就像JimmyJ说的,你仍然需要清理你的数据 ! 使用 PDO,你仍然可以在数据库中保存类似 <?php phpinfo();?>的东西。 好的,这个例子不会损害任何东西,但它可能是其他任何东西而不是 phpinfo 。

...