mysql_real_escape_string()能够完全防止SQL注入吗?

38

justinshattuck.com 在 Chrome 上给了我一个恶意软件警告,也许他的网站也被黑客攻击了。 - user967451
1
您注入字符串中的字符并非真正的BIG5编码。一些供应商将日文假名包含在BIG5编码中,但标准并未包含假名。 - Windows programmer
4个回答

24

根据Stefan Esser的说法,当使用SET NAMES时,mysql_real_escape_string()是不安全的。

他在博客中解释道:

SET NAMES通常用于将编码从默认值切换到应用程序所需的编码。这是以一种mysql_real_escape_string不知道的方式完成的。这意味着,如果您切换到某些允许反斜杠作为第2、3、4...个字节的多字节编码,则会遇到问题,因为mysql_real_escape_string无法正确转义。UTF-8是安全的...

更改编码的安全方法是使用mysql_set_charset,但这仅适用于新的PHP版本。

他确实提到了UTF-8是安全的。


3
"UTF-8是安全的..."这句话引出了另一个鲜为人知的问题:输入编码安全。例如,您是否检查输入(如GET/POST/COOKIE/...)是否真的是UTF-8?自动输入编码检查和转换是否激活(无论是在服务器级别还是应用程序级别)?等等。 - Halil Özgür

19

这是一个MySQL服务器的bug,据报告在2006年5月就已经修复。

请参阅:

该漏洞在MySQL 4.1.20、5.0.22和5.1.11中报告已修复。

如果您使用的是4.1.x、5.0.x或5.1.x,请确保您至少升级到小版本号。

作为解决方法,您还可以启用SQL模式NO_BACKSLASH_ESCAPES,该模式禁用反斜杠作为引号转义字符。


如果您使用 NO_BACKSLASH_ESCAPES,那么您就不能使用双引号"字符来引用您的文字 - eggyal
@eggyal,我可以问一下你为什么这么说吗?尝试使用SELECT "O""Hare"; - Bill Karwin
跟随链接!在NO_BACKSLASH_ESCAPES模式下,mysql_real_escape_string()仅会将'字符加倍,而不是"字符! - eggyal
@eggyal,啊,谢谢,这很好知道。无论如何,应该使用标准的 ' 作为字符串定界符。 - Bill Karwin
1
确实如此,这就是为什么在那篇文章中我建议设置ANSI_QUOTES模式来强制执行这种行为。 - eggyal

3

我相信只有在使用SQL更改字符编码时才会出现问题。


1

正如其他人所展示的那样,mysql_real_escape_string()在某些边缘情况下可能会被绕过。这是一个已知的绕过转义逻辑的策略,但可能还有其他未被发现的漏洞。

在PHP中预防SQL注入的简单而有效的方法是尽可能使用预处理语句,在不能使用时使用非常严格的白名单。

预处理语句,在实际使用并且不是PDO驱动程序模拟时,可以证明是安全的(至少在防止SQL注入方面),因为它们解决了应用程序安全的一个根本问题:将数据与操作数据的指令分离。它们被发送到单独的数据包中;参数化的值永远没有机会污染查询字符串。

现在已经是2015年了。不要再进行转义和连接。您仍然应根据应用程序(和业务)逻辑验证输入,但只需使用预处理语句即可。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接