为了防止SQL注入,建议将prepared statement与bind values一起使用。这样可以确保数据库可以区分SQL中的实际逻辑(必须进行解析,解释和优化)和数据(不需要解释),因此不会解释和执行数据中找到的命令。 。
实现某种保护的另一种方法是使用转义库,它可以解除数据中的重要字符的武装,因此将不会对其进行解释。
在我看来,通常建议将绑定参数与转义一起使用预备语句而不是转义输入。例如,带有[[bind values的Prepared statement
确实在循环中具有一些性能优势。我的问题:是否有安全上的理由更倾向于将绑定值与转义结合使用?如果是的话,确切的原因是什么?
我可能想到的一个原因是“转义很棘手”,转义库需要与数据库功能完全匹配……还有其他吗?$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 (?, ?, ?, ?, ?, ?)";
查询参数对于更多数据类型来说是安全的,它们可帮助您更快地编写代码,并减少错误。这是一个很大的胜利。
转义可以解除数据中重要字符的武器
坦率地说,这是胡说八道。没有包罗万象的“重要字符”。如果一个字符被放开,可能会对一个查询部分造成毁灭性影响,而与另一个查询部分的羔羊一样无害。反之亦然。
没有抽象的,包罗万象的“数据”。所有查询部分都是不同的,但转义仅适用于一部分。
- 并且
- 没有这样的做法之类的,例如“使用转义进行保护”。
转义用于转义SQL字符串中的 特殊字符。而且从未打算提供任何保护。这只是一种被严重误解和虐待的技术措施。就像声称我们在程序中遵循正确的语法只是为了保护。我们遵循正确的语法来使解释器/编译器理解我们的代码。同样在这里。转义用于产生语法正确的字符串。当然这是防注射的副作用。但是字符串不是查询中唯一使用的数据类型。并且在任何其他数据文字上使用它是通往灾难的直接之路。
此外,即使对于字符串,转义本质上也是可拆卸的措施,它仅构成一整套蠕虫,使您的代码容易出现各种人为错误。引用我对此事的文章,Why should I use prepared statements if escaping is safe?:如您所见,格式化数据库的值
有效地分为两部分,在查询中转义变量并引用值。这就是所有不可思议的事情发生导致SQL注入无数现实生活中的情况
的原因。通过您的简化示例,其中所有代码都绑定在一起,很难忽略正确的例程。但是在现实生活中,代码要复杂得多,它由多个不同的模块组成。转义在一个模块中完成,而在另一个模块中引用。或不。没人能说出来。我只是相信这个值已经被转义了。否则我只是为了确定要转义它,并在数据中引入额外的转义字符。或者我是一个新开发人员,不了解您在此处发布的示例,而我正在观看一个YouTube视频,该视频显示转义可以防止SQL注入。我知道该值已经被转义,因此可以安全地放入查询中。而且因为它是整数,所以为什么要在其上浪费引号? 或者我知道数据进入应用程序时已经被转义了,所以以后在某些内部操作(例如,移到另一个表中)时,我就不必转义了。并因此获得了一流的二阶SQL注入。相信我,我在野外看到了所有这些情况。这种分开的格式会带来一团糟,并且浪费了注入的机会。
与转义不同,准备好的语句始终确保正确处理查询部分。