如果所有表都使用 Latin1 编码,mysql_escape_string 是否有任何安全漏洞?

信息安全 php 数据库 sql注入
2021-08-28 05:05:37

我听说 PHP 函数mysql_escape_string存在与多字节字符相关的安全漏洞。如果所有表都使用 Latin1 编码,是否存在漏洞?

3个回答

问题是mysql_escape_string()不检查数据库的字符编码。结果mysql_escape_string()将不知道您的数据库编码,并且可能将多字节字符视为单字节字符。这可能导致最后两个字节被转义为保留字符,例如与 SQL 引擎具有特殊相关性的无数其他字符。

在这种情况下,攻击者可以附加额外的 SQL 命令来访问不希望的数据或功能。这就是为什么不推荐使用该功能并mysql_real_escape_string()建议使用的原因。

mysql_real_escape_string()工作原理几乎相同,只是它连接到数据库以确定数据库使用什么编码,防止已知的多字节转义问题。

还要注意的是mysql_escape_string() ,并mysql_real_escape_string() 没有逃避%和_字符(根据手动参考http://php.net/manual/en/function.mysql-escape-string.phphttp://php.net/manual/ en/function.mysql-real-escape-string.php见注释)。这可能允许访问与关键字(例如 )一起使用时不打算使用的数据LIKE,因此应特别小心。


更新

那么,mysql_escape_string 假设什么编码?

我相信它是 ASCII,但是我无法确认这一点。无论如何,这对结果没有影响;如果未正确编码,使用 Latin1 进行数据库编码可能会导致安全漏洞。

另请注意,这不仅仅是数据库的漏洞。在应用程序/服务器端脚本中,处理输入时必须小心,以了解字符串如何从函数传递到函数并确保保留正确的编码。理想情况下,端到端使用 UTF-8 会很好,但并不总是一种选择。

就个人而言,我认为你问错了问题。如果你想避免 SQL 注入漏洞——你也应该这样做——答案是不要mysql_escape_string更小心地使用。正确的答案是使用准备好的语句。

根本问题是它mysql_escape_string很脆弱,很难预测它可能会以何种具体方式破坏。你已经了解了脆弱性的一个来源mysql_escape_string,现在想知道这是否是唯一的来源。

就个人而言,我吸取了不同的教训。我吸取的教训是,如果安全是工作,那么工作mysql_escape_string的工具就是错误的。相反,您应该使用准备好的语句(参数化查询)。

在安全领域,人们普遍认为避免 SQL 注入的最可靠方法是使用预准备语句。不要尝试转义/编码您的数据,然后使用字符串连接构建 SQL 查询;这种方法很脆弱,如果数据库对您的查询的解释与您预期的不同,则很容易破坏。所以我的建议是:不要试图变得聪明——只要使用准备好的陈述并快乐。

根据@BernieWhite 的回答mysql_escape_string()在完全不了解实际用于数据库连接的字符串编码(与表中使用的字符串编码不同)的情况下执行转义。

因此,它试图'通过\'在出现时替换它们来转义字符它以字节为基础执行此操作,替换每次出现的0x27with 0x5c27(即它在假设字符串被编码为 ASCII 的单字节超集的假设下有效地运行);例如,它会将字符串转换0xbf270xbf5c27——但如果连接编码是 GBK,这会将无效的字符串转换为縗'(注意未转义的'字符)。

因此mysql_real_escape_string()被引入以正确执行转义,即根据连接字符编码。但是,因此必须通过调用通知客户端库字符编码mysql_set_charset()——这一步经常被忽略,并且就像使用原始代码一样容易受到攻击mysql_escape_string()

但即使有人使用mysql_real_escape_string(),仍然有其他边缘情况可能让您容易受到攻击。正如我在 StackOverflow 上对“绕过 mysql_real_escape_string() 的 SQL 注入”的回答中所解释的:

TL;博士

mysql_real_escape_string()如果出现以下情况,将不会提供任何保护(并且可能进一步破坏您的数据):

  • MySQL 的NO_BACKSLASH_ESCAPESSQL 模式已启用(可能会启用,除非您明确选择另一种 SQL 模式);

  • 您的 SQL 字符串文字使用双引号"字符引用。

由于在确保安全处理嵌入的字符串文字方面存在这些实际困难,因此通常建议不要尝试!相反,可以将字面值以与 SQL 完全分离的数据包的形式发送到数据库连接;因此,服务器甚至不会尝试将这些值解析为其他任何内容:这被称为“查询参数化”,这是@DW 的答案所暗示的,并且在如何防止 PHP 中的 SQL 注入中得到了很好的解释?