【发布时间】:2011-06-13 21:45:26
【问题描述】:
我有一个应用程序,它可以通过将动态 mysql 查询与 mysql (mysqli) 真正的转义字符串结合使用而受益匪浅。如果我通过 mysql real escape 运行从用户那里收到的所有数据,它会和使用 mysql 准备语句一样安全吗?
【问题讨论】:
标签: mysql security sql-injection prepared-statement
我有一个应用程序,它可以通过将动态 mysql 查询与 mysql (mysqli) 真正的转义字符串结合使用而受益匪浅。如果我通过 mysql real escape 运行从用户那里收到的所有数据,它会和使用 mysql 准备语句一样安全吗?
【问题讨论】:
标签: mysql security sql-injection prepared-statement
是的,但有条件的是。
您需要正确转义 100% 的输入。并且您需要正确设置字符集(如果您使用的是 C API,则需要调用mysql_set_character_set() 而不是SET NAMES)。如果你错过了一件小事,你就会很脆弱。所以是的,只要你做对了……
这就是很多人会推荐准备好的查询的原因。不是因为它们更安全。但因为他们更宽容...
【讨论】:
mysql_real_escape_string() 用于字符串,整数转换用于整数等,以及将字符串值作为标识符添加到查询中的排序/其他操作的白名单字段名称)。
虽然标题中的问题模棱两可,可以解释为“动态 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 准备好的语句一样安全?
遵循这些规则 - 是的,它与原生预处理语句一样安全。
【讨论】:
我认为@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']}'";
?>
当我说“曾经这样做”时,我的意思是我最终放弃并开始使用准备好的语句!
【讨论】: