为啥使用 mysql 准备好的语句比使用常见的转义函数更安全?

Posted

技术标签:

【中文标题】为啥使用 mysql 准备好的语句比使用常见的转义函数更安全?【英文标题】:Why is using a mysql prepared statement more secure than using the common escape functions?为什么使用 mysql 准备好的语句比使用常见的转义函数更安全? 【发布时间】:2010-10-18 11:14:29 【问题描述】:

另一个问题中有一条评论如下:

“当涉及到数据库查询时, 总是尝试使用准备好的 参数化查询。 mysqli 和 PDO 库支持这一点。这是 比使用转义更安全 功能如 mysql_real_escape_string。”

Source

那么,我想问的是:为什么准备好的参数化查询更安全?

【问题讨论】:

【参考方案1】:

我认为这里的人们缺少的重要一点是,使用支持参数化查询的数据库,无需担心“转义”。数据库引擎不会将绑定的变量组合到 SQL 语句中,然后解析整个事情;绑定的变量是独立的,永远不会被解析为通用 SQL 语句。

这就是安全性和速度的来源。数据库引擎知道占位符仅包含数据,因此它永远不会被解析为完整的 SQL 语句。当您准备一个语句然后多次执行它时,速度就会提高;将多条记录插入同一个表的规范示例。这种情况下,数据库引擎只需要解析、优化等一次。

现在,一个问题是数据库抽象库。他们有时会通过将绑定变量插入到带有适当转义的 SQL 语句中来伪造它。不过,这比自己做要好。

【讨论】:

所以速度更快但安全性相同?我的意思是你不能比完全安全更安全。我还想要一些速度理论的证据。【参考方案2】:

首先,您将危险字符的转义留给数据库,这比您人类安全得多。

...它不会忘记逃跑,也不会错过任何可用于注入恶意 SQL 的特殊字符。更不用说,您可能会在启动时获得性能提升!

【讨论】:

但是数据库如何知道危险和我真正想要它做的事情之间的区别? 它知道哪些字符是邪恶的,所以它应该在 MySQL 中的邪恶字符之前添加转义字符“\”。这仍然会按原样执行查询,但不会尊重绑定中出现的任何特殊字符。 还要注意,您单独指定“绑定”(未在查询中连接),只需在查询中将占位符插入到它们应该出现的位置。数据库(我想,也许是 PDO 做到了?)然后在绑定中转义字符。 我现在明白了。非常感谢您的帮助:P【参考方案3】:

我对安全性不是很精通,但这里有一个解释,希望对您有所帮助:

假设您有这样的声明:

从 mydb 中选择 [整数]

假装当你准备它时,该语句在我们想象的 sql 实现中被编译成字节。

           01                  00 00                  23
Opcode for select          Prepared bytes      number of "mydb"
                          for your integer

现在,当您执行时,您会将数字插入为准备好的语句保留的空间中。

如果你只是使用转义,你可能会在其中插入尽可能多的乱码,并可能导致内存溢出,或者一些他们忘记转义的奇怪 sql 命令。

【讨论】:

【参考方案4】:

因为使用准备好的语句,您不能忘记转义内容。所以没有办法引入不安全感。

如果您记得每次调用 mysql_query 时都使用 mysql_real_escape_string,则 mysql_real_escape_string 与准备好的语句一样安全,但很容易忘记。

【讨论】:

【参考方案5】:

准备好的语句解决了fundamental problem of application security 单纯的数据清理无法解决的问题:它们导致数据和指令完全分离。当两者混淆时,结果就是不安全。 SQL 注入和缓冲区溢出都是如此。

(还有其他不安全的方法。)

【讨论】:

【参考方案6】:

最好的情况,可能不是,但至少同样安全;为什么要冒险?

【讨论】:

【参考方案7】:

由于此漏洞http://shiflett.org/blog/2006/jan/addslashes-versus-mysql-real-escape-string,该函数不安全。这就是为什么首选准备好的语句并且它也可以提高性能的原因。

【讨论】:

我相信,如果我正确阅读了链接的博客,他的问题是 addlashes 不安全,而不是 mysql_real_escape_string。他最后说,后者是一个有效的选择,如果人们记得这样做,但人们往往会忘记调用它。使用准备好的语句有助于解决内存问题。 这也是一个有趣的链接,它指出了 mysql_real_escape_string 的一个潜在问题,虽然很模糊:ilia.ws/archives/…

以上是关于为啥使用 mysql 准备好的语句比使用常见的转义函数更安全?的主要内容,如果未能解决你的问题,请参考以下文章

MySQL 准备好的语句

使用准备好的语句将多个带前缀的表移动到存档数据库,为啥这个 MySQL 语句无效?

在 Java 中转义 MySQL 字符串...没有准备好的语句

没有准备好的语句的 SQL 中的转义字符

为啥mysql.connecter python准备好的语句在bytearray中返回字符串

对于 postgresql,java sql 准备好的语句不能正确转义