为什么mysql_real_escape_string()不应该避免任何SQL注入


Why mysql_real_escape_string() shouldn't avoid any SQL Injection?

我听到有人说(关于C#/SQL Server,也与PHP/MySql有关(:不要手动转义字符串 - 改用存储过程

好的,我可以接受这个建议,但为什么呢?许多人说(包括在SO上(mysql_real_escape_string()就足够了,mysql_real_escape_string()很好,mysql_real_escape_string()是第一种保护方式。

为什么?有没有mysql_real_escape_string()会失败的情况?至少一个...我不需要很多:)

当mysql_real_escape_string失败时:

$sql = "SELECT * FROM users WHERE id=" + mysql_real_escape_string($_GET['id']);

如果$_GET['user_id']设置为 1 OR 1=1,则没有特殊字符,也不会对其进行筛选。

结果:返回所有行。

情况变得更糟。怎么样...如果$_GET['user_id']设置为 1 或 is_admin = 1 怎么办?

该函数仅设计为在单引号内使用。

mysql_real_escape_string

两件事可能会出错:

  • 你可以忘记使用它
  • 如果您使用的是某些特定的多字节连接编码,并且您已经将这些编码设置为 SET NAMES 而不是mysql_set_charset,它仍然会使您容易受到攻击

更新:

  • 使用 UTF-8 是安全的(尽管这并不意味着您应该继续使用 SET NAMES
  • 有关说明,请参阅此处

仅供参考: mysql_real_escape_string()逃脱不了%_.如果与 LIKE, GRANT, or REVOKE 结合使用,这些是 MySQL 中的通配符。

mysql_real_escape_string()可能无法清理输入。由于mysql_real_esacpe_string()在清理字符串时会考虑字符集。问题来了。您可以通过发送查询以更改连接的字符集mysql_query函数来更改字符。但是,mysql_real_escape_string()会忘记您正在使用的集合,并且它会不正确地转义某些字符。

另一件事是不断手动调用它。即使将其包装在函数中也是P.I.T.A.,因为它意味着您必须创建自己的某种数据库包装器/数据库抽象层,以便能够自动调用mysql_real_escape_string()

这就是为什么我们在PHP中有PDO来帮助我们缓解上述所有问题,并且您可以使用参数化的预准备语句,这是处理更改数据的重复查询的首选方法。

准备语句,绑定输入变量,它将根据正在使用的数据库驱动程序和连接的字符集清理输入。它的代码更少,完全安全。

关于 mysql_real_escape_string(( 和 SQL 注入只有一件事——

前者与后者没有丝毫关系。

虽然这听起来很矛盾,但没有什么比这更真实了。

这里有2个陈述证明了这一点

  1. 您只需要转义带引号的字符串,因为此函数无济于事。
  2. 事实上,您必须转义要添加到查询中的每个字符串,即使是最安全的字符串。 只是因为它可能包含一些特殊字符,从而破坏查询(只是意外,而不是恶意情节(。

因此,在适用的情况下,无论如何都必须使用此功能,无论存在什么危险或恐惧。在任何其他情况下,它都无济于事。

我唯一要补充的是,准备好的语句也不能提供完全保护。以下是解释和建议: https://stackoverflow.com/a/8255054/285587