带有 sql 转义的动态 mysql 查询是不是与准备好的语句一样安全?

Posted

技术标签:

【中文标题】带有 sql 转义的动态 mysql 查询是不是与准备好的语句一样安全?【英文标题】:Are dynamic mysql queries with sql escaping just as secure as prepared statements?带有 sql 转义的动态 mysql 查询是否与准备好的语句一样安全? 【发布时间】:2011-06-13 21:45:26 【问题描述】:

我有一个应用程序,它可以通过将动态 mysql 查询与 mysql (mysqli) 真正的转义字符串结合使用而受益匪浅。如果我通过 mysql real escape 运行从用户那里收到的所有数据,它会和使用 mysql 准备语句一样安全吗?

【问题讨论】:

【参考方案1】:

是的,但有条件的是。

您需要正确转义 100% 的输入。并且您需要正确设置字符集(如果您使用的是 C API,则需要调用mysql_set_character_set() 而不是SET NAMES)。如果你错过了一件小事,你就会很脆弱。所以是的,只要你做对了……

这就是很多人会推荐准备好的查询的原因。不是因为它们更安全。但因为他们更宽容...

【讨论】:

perpared 语句有 2 次往返,准备和执行。每次在变量上运行 mysql 转义字符串是否算作数据库往返? @bshack:我不这么认为。它使用来自开放连接的字符集,因此它不需要往返(但我可能是错的,我没有检查 API 的源代码,只有 the documentation )... 除了设置字符集还有什么需要做的吗? @Michael:如果你正确地逃避了一切,那么不会。 (正确转义意味着 mysql_real_escape_string() 用于字符串,整数转换用于整数等,以及将字符串值作为标识符添加到查询中的排序/其他操作的白名单字段名称)。 @Michael 是的,当然。您必须始终引用您转义的数据。否则逃跑也没有半点好处。 ircmaxell 肯定知道这一点,但这一点非常明显,以至于每个人总是忘记提及它,但它是 essential* 的事情。【参考方案2】:

绝对没有。

虽然标题中的问题模棱两可,可以解释为“动态 mysql 查询是否具有每个部分正确格式化... ",因此有一个肯定的答案,正文中的问题是不是

如果我通过 mysql real escape 运行从用户那里收到的所有数据,它会和使用 mysql 准备语句一样安全吗?

如果你仔细看这个问题,你会明白这只是一个魔术引号的化身!这个不光彩、已弃用和删除的功能的真正目的正是“通过转义运行所有用户输入”。 现在每个人都知道魔术语录很糟糕。 那为什么要正面回答呢?

好吧,看来还是需要再解释一下,为什么批量转义不好。

问题的根源是一个相当强烈的错觉,几乎每个 php 用户都有这种错觉: 每个人都有一个奇怪的信念,即逃避对“危险人物”(他们是什么?)做一些事情,使他们“安全”(如何?)。不用说,这只是一个完全的垃圾。

事实是:

转义不会“清理”任何内容。 逃逸与注射无关。 转义与用户输入无关。

转义只是一种字符串格式而已。 当您需要时 - 尽管有注射可能性,您仍需要它。 当你不需要它时——它对注射没有一点帮助。

说到与prepared statements的区别,至少有一个问题(在sql-injection标签下已经多次提到): 像这样的代码

$clean = mysql_real_escape_string($_POST['some_dangerous_variable']);
$query = "SELECT * FROM someTable WHERE somevalue = $clean";

将帮助您不反对注射。 因为转义只是一种字符串格式化工具,绝不是注入防止器。 去搞清楚。

但是,转义与准备好的语句有一些共同点: 如果

,他们都不能保证你不会被注射 您仅将它用于臭名昭著的“用户输入”,而不是作为构建任何查询的严格规则,尽管有数据源。 如果您需要插入的不是数据而是标识符或关键字。

为了在这些情况下安全起见,请参阅我的回答,解释FULL sql injection protection how-to

长话短说:只有在最初的陈述中做出 2 项必要的更正和一项补充时,您才能认为自己是安全的:

如果我通过 mysql real escape运行所有从用户接收到的数据并始终将其括在引号中(并且,正如 ircmaxell 所提到的,mysqli_set_charset() 用于mysqli_real_escape string() 确实有效(在这种罕见的情况下使用一些奇怪的编码,如 GBK))是否与使用 mysql 准备好的语句一样安全?

遵循这些规则 - 是的,它与原生预处理语句一样安全。

【讨论】:

对不起;我不是要挑剔什么的,而是……“他们都不能保证……” 对不起,你是在语法还是意义?如果以前 - 请随时编辑我的帖子,我将不胜感激。我不是母语人士,有时看不到我的缺点。【参考方案3】:

我认为@ircmaxell 做得对。

作为后续行动,请注意此类事情。 我以前一直这样做:

<?php

//sanitize the dangerous posted variable...
$clean = mysql_real_escape_string($_POST['some_dangerous_variable']);

//...and then forget to use it!
$query = "SELECT * FROM someTable WHERE somevalue = '$_POST['some_dangerous_variable']'";

?>

当我说“曾经这样做”时,我的意思是我最终放弃并开始使用准备好的语句!

【讨论】:

以上是关于带有 sql 转义的动态 mysql 查询是不是与准备好的语句一样安全?的主要内容,如果未能解决你的问题,请参考以下文章

MySql数据库-查询插入数据时转义函数的使用

mysql中查询语句的表名,是不是可以动态选择表名像这样

避免mysql注入应该避免都有哪些特殊字符

SQL Server 到 Mysql 的迁移(使用 Mysql Workbench)。如何在 Workbench 向导的步骤中添加带有手动转义撇号的数据?

带有 IN 子句的 SQL 查询的 MYSQL 查询优化

对MySQL DB进行动态SQL查询