我已经阅读了各种文档(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注入中保存用户?
由于
答案 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注入攻击的唯一通用方法。通常,尝试过滤不受信任的输入数据会被破坏。