具有转义参数的内插语句对具有绑定参数的预备语句的原因

问题描述 投票:2回答:2

为了防止SQL注入,建议将prepared statementbind values一起使用。这样可以确保数据库可以区分SQL中的实际逻辑(必须进行解析,解释和优化)和数据(不需要解释),因此不会解释和执行数据中找到的命令。 。

实现某种保护的另一种方法是使用转义库,它可以解除数据中的重要字符的武装,因此将不会对其进行解释。

在我看来,通常建议将绑定参数转义一起使用预备语句而不是转义输入。例如,带有[[bind values的Prepared statement

确实在循环中具有一些性能优势。

我的问题:是否有安全上的理由更倾向于将绑定值转义结合使用?如果是的话,确切的原因是什么?

我可能想到的一个原因是“转义很棘手”,转义库需要与数据库功能完全匹配……还有其他吗?
sql sql-injection
2个回答
4
投票
原因是转义仅用于保护带引号的字符串文字。例如(由于您未引用任何特定的编程语言,因此我将使用伪代码):

$escapedName = EscapeString("O'Reilly") $sql = "SELECT * FROM MyTable WHERE name = '$escapedName'"

在上面的示例中,撇号应转义,因此它将变为WHERE name = 'O\'Reilly',因此可以安全地插入SQL查询而不会引起任何错误。

但是,不需要在SQL中用数字引号,并且转义包含撇号的字符串不会做正确的事情:

$escapedId = EscapeString("123'456") $sql = "SELECT * FROM MyTable WHERE id = $escapedId"

这将导致WHERE id = 123\'456仍然是错误。

[您可能会说,“把数字放在单引号中,但这并不总是可能的,例如,MySQL中的LIMIT子句需要实整数,而不是包含数字的带引号的字符串。

除了上述问题,使用参数而不是使用转义来编写代码只是[[简易!

例如,您可以编写如下代码:

$sql = "INSERT INTO mytable (col1, col2, col3, col4, col5, col6) VALUES ('" . mysqli_real_escape_string($_POST['col1']) . "', " . $mysqli->real_escape_string($_POST['col2']) . "', '" . $mysqli->real_escape_string($_POST['col3']) . "', '" . $mysqli->real_escape_string($_POST['col4']) . ", '" . $mysqli->real_escape_string($_POST['col5']) . "', '" . $mysqli->real_escape_string($_POST['col6']) . "')";

您能发现错误吗?只要有足够的时间,我相信您可以。但这会减慢您的编码速度,并且在寻找缺少引号字符和其他错误时可能会给您带来疲劳感。

但是写起来很容易,事后也更容易阅读:

$sql = "INSERT INTO mytable (col1, col2, col3, col4, col5, col6) VALUES (?, ?, ?, ?, ?, ?)";

查询参数对于更多数据类型来说是安全的,它们可帮助您更快地编写代码,并减少错误。这是一个很大的胜利。


0
投票

转义可以解除数据中重要字符的武器

坦率地说,这是胡说八道。

没有包罗万象的“重要字符”。如果一个字符被放开,可能会对一个查询部分造成毁灭性影响,而与另一个查询部分的羔羊一样无害。反之亦然。

    没有抽象的,包罗万象的“数据”。所有查询部分都是不同的,但转义仅适用于一部分。
  • 并且
  • 没有这样的做法之类的,例如“使用转义进行保护”。
  • 转义用于转义SQL字符串中的

    特殊字符。而且从未打算提供任何保护。这只是一种被严重误解和虐待的技术措施。就像声称我们在程序中遵循正确的语法只是为了保护。我们遵循正确的语法来使解释器/编译器理解我们的代码。同样在这里。转义用于产生语法正确的字符串。当然这是防注射的副作用。但是字符串不是查询中唯一使用的数据类型。并且在任何其他数据文字上使用它是通往灾难的直接之路。

    此外,即使对于字符串,转义本质上也是可拆卸的措施,它仅构成一整套蠕虫,使您的代码容易出现各种人为错误。引用我对此事的文章,Why should I use prepared statements if escaping is safe?

    如您所见,格式化数据库的值

    有效地分为两部分,
    在查询中转义变量并引用值。这就是

    所有不可思议的事情发生导致SQL注入无数现实生活中的情况

    的原因。 通过您的简化示例,其中所有代码都绑定在一起,很难忽略正确的例程。但是在现实生活中,代码要复杂得多,它由多个不同的模块组成。转义在一个模块中完成,而在另一个模块中引用。或不。没人能说出来。我只是相信这个值已经被转义了。否则我只是为了确定要转义它,并在数据中引入额外的转义字符。或者我是一个新开发人员,不了解您在此处发布的示例,而我正在观看一个YouTube视频,该视频显示转义可以防止SQL注入。我知道该值已经被转义,因此可以安全地放入查询中。而且因为它是整数,所以为什么要在其上浪费引号? 或者我知道数据进入应用程序时已经被转义了,所以以后在某些内部操作(例如,移到另一个表中)时,我就不必转义了。并因此获得了一流的二阶SQL注入。

    相信我,我在野外看到了所有这些情况。这种分开的格式会带来一团糟,并且浪费了注入的机会。

  • 与转义不同,准备好的语句始终确保正确处理查询部分。

    © www.soinside.com 2019 - 2024. All rights reserved.