准备语句如何在下面的语句

时间:2015-04-24 07:11:11

标签: php pdo prepared-statement

我已经阅读了各种文档(SO帖子),关于PDO的准备语句如何保护用户免受SQL注入。

虽然,我理解它保护用户,因为在准备好的语句中,用户记录直接没有在服务器上执行insted我们正在发送位置/命名参数(?/:name)然后我们在execute语句中发送实际数据,并且因为它使我们免于SQL注入。

好吧,现在,如果我有以下SQL代码:

$query = "select * from user where id = $user_input_id";

和用户输入id = 1

所以查询将类似于:

$query = "select * from user where id = 1"; 

到目前为止,这是完美的。但是,如果用户entre $ id =“1; DROP TABLE用户;”所以查询将是这样的:

$query    = "SELECT * FROM users where id=$id";

因此,它将执行

$query = "SELECT * FROM users where id=1; DROP TABLE users;";

它的工作原理和用户表将会丢失,因为此查询直接执行:

好吧,我已经读过预备语句可以保存用户:

和准备好的声明像:

$data = "1; DROP TABLE users;"

$db->prepare("SELECT * FROM users where id=?");

$db->execute($data);

在execute语句中,带Drop表的记录正在传递,那么它究竟是如何不执行drop table statament的呢?执行还在服务器上执行某些部分吗?

任何人都可以解释一下这里准备好的语句如何从SQL注入中保存用户?

由于

3 个答案:

答案 0 :(得分:2)

如果没有明确设置类型(请参阅PDOStatement::bindValue()的示例),它会将传递的值视为字符串,因此它将有效地执行此操作:

SELECT * FROM users where id='1; DROP TABLE users;'

顺便说一句,如果您使用模拟预处理语句(PDO::ATTR_EMULATE_PREPARES),这实际上会发生;没有它,它将首先发送参数化查询,然后是实际数据。

答案 1 :(得分:1)

这就是为什么您可以另外将绑定数据类型设置为所需类型的原因。

$stm->bindParam(":id", $id, PDO:PARAM_INT)

此外,PDO会对数据进行一些转义,并且您提供的字符串不会破坏;处的查询,但会在数据库中作为纯字符串插入。

答案 2 :(得分:1)

SQL注入是对SQL解析步骤的攻击,而不是语句执行步骤。在这方面,它与其他解析攻击(如跨站点脚本和XML注入攻击)具有相似性。

SQL注入是有效的,因为通过使用字符串连接运算符将代码和(不可信)数据组合在一个字符串中来创建SQL语句的常见(损坏)技术允许特制字符串违反语句数据协议的可能性(通常通过使用嵌入在数据中的字符串分隔符来突破数据上下文),并允许攻击者操纵SQL解析器执行与最初预期的不同的代码。

当一个人使用预准备语句时,会告诉解析器“将该语句视为纯信任代码,并提供一些插槽,我将插入数据以供执行”。

当你丢弃字符串'1;将表用户放入使用'?'创建的数据槽中占位符,解析器不处理该字符串,因此它没有机会影响字符串的解析:您使字符串的内容无法突破数据上下文。

使用您的示例,数据库将执行等效语句:

SELECT * FROM users where id =“1; drop table users;”

这是一个完全有效的select语句,它可能会也可能不会返回行,具体取决于表中的数据,但几乎肯定无法正常工作。

然而,该方法绕过了SQL注入的尝试。

请注意:使用预准备语句是避免SQL注入攻击的唯一通用方法。通常,尝试过滤不受信任的输入数据会被破坏。