使用sql转义的动态mysql查询是否与预准备语句一样安全?

bsh*_*ack 10 mysql security sql-injection prepared-statement

我有一个应用程序,通过结合mysql(mysqli)真正的转义字符串使用动态mysql查询将大大受益.如果我通过mysql运行从用户收到的所有数据真正的转义它会像使用mysql预处理语句一样安全吗?

irc*_*ell 17

是的,但是合格的是.

你需要正确地逃避100%的输入.并且您需要正确设置字符集(如果您使用的是C API,则需要调用mysql_set_character_set()而不是SET NAMES).如果你错过了一件小事,那你很脆弱.所以是的,只要你做的一切都正确......

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


You*_*nse 4

绝对不。

虽然标题中的问题不明确,可以解释为“动态 mysql 查询的每个部分都格式正确吗……”,因此有一个肯定的答案,但正文中的问题不是

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

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

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

问题的根源是一个相当强烈的错觉,几乎每个 PHP 用户都有这样的想法:
每个人都有一个奇怪的信念,即转义会对“危险字符”(它们是什么?)做一些事情,使它们“安全”(如何?)。不用说,这完全是垃圾。

事实是:

  • 逃避不会“净化”任何东西。
  • 逃跑与注射无关。
  • 转义与用户输入无关。

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

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

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

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

然而,转义与准备好的语句有一些共同点:
它们都不能保证您不被注入,如果

  • 您仅将其用于臭名昭著的“用户输入”,而不是作为构建任何查询的严格规则,无论数据源如何。
  • 如果您需要插入的不是数据而是标识符或关键字。

为了在这些情况下安全起见,请参阅我的回答,解释完整的 SQL 注入保护方法

长话短说:只有对最初的陈述进行两项必要的更正和一项补充,您才能认为自己是安全的:

如果我通过 mysql real escape运行从用户接收到的所有数据,并始终将其括在引号中(并且,正如 ircmaxell 提到的,mysqli_set_charset()用于使 mysqli_real_escape string() 实际上完成它的工作(在使用一些奇怪的编码的罕见情况下,例如GBK)) 它会和使用 mysql 准备好的语句一样安全吗?

遵循这些规则 - 是的,它将像本机准备好的语句一样安全。