【问题标题】: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 准备语句一样安全吗?

【问题讨论】:

    标签: mysql security sql-injection prepared-statement


    【解决方案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']}'";
    
    ?>
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-07
      • 2011-09-11
      • 2011-08-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-14
      相关资源
      最近更新 更多