mysqli_real_escape_string()中默认字符集的安全含义是什么意思?

时间:2015-06-02 23:33:25

标签: php security mysqli

在mysqli_real_escape_string()的PHP文档中,写的是

  

注意   安全性:默认字符集

     

字符集必须在服务器级别设置,或者使用   API函数mysqli_set_charset()让它影响   mysqli_real_escape_string()。

来源mysqli_real_escape_string

在关于字符集的进一步链接中,提到了

  

应该理解和定义字符集,因为它具有   影响每一个行动,并包括安全隐患。

Suource Character sets

为了安全起见,为什么必须设置字符集以及它包含哪些安全隐患? 任何人都可以解释这些背后的概念吗?

提前致谢

2 个答案:

答案 0 :(得分:4)

如何解析SQL查询取决于连接字符集。如果您执行了此查询:

$value = chr(0xE0) . chr(0x5C);
mysql_query("SELECT '$value'");

然后如果连接字符集是Latin-1,MySQL会看到无效:

SELECT 'à\'

如果字符集是Shift-JIS,则字节序列0xE0,0x5C将被解释为双字节字符:

SELECT '濬'

为安全性添加字符串文字转义:

$value = mysql_real_escape_string($value);
mysql_query("SELECT '$value'");

现在,如果您使用mysql_set_charset正确地将连接字符集设置为Shift-JIS,MySQL仍会看到:

SELECT '濬'

但是如果你没有设置连接字符集,并且MySQL的默认字符集是Shift-JIS但是PHP的默认字符集是ASCII,那么PHP不知道尾随的0x5C字符是双字节序列的一部分并且逃避它,认为它正在生成有效的输出:

SELECT 'à\\'

虽然MySQL使用Shift-JIS将其读取为:

SELECT '濬\'

使用反斜杠转义尾随',这会使字符串文字保持打开状态。查询中的下一个'字符将结束字符串,留下原始SQL内容中的后续内容。如果你可以在那里注入,那么查询就容易受到攻击。

此问题仅适用于少数东亚编码,例如Shift-JIS,其中多字节序列可以包含字节,这些字节本身就是反斜杠等有效的ASCII字符。如果不匹配的编码都将低字节视为始终为ASCII(严格的ASCII超集,如拉丁-1与UTF-8的更常见的不匹配),则不会出现这种混淆。

幸运的是,默认使用这些编码的服务器并不常见,因此在实践中这是一个很少可利用的问题。但如果您 使用mysql_real_escape_string,那么您应该正确行事。 (最好通过使用参数化查询来完全避免它。)

答案 1 :(得分:1)

如果您想secure your applications against SQL injection,则应该使用预备语句而不是转发输入。 (不要让MySQLi或PDO模拟准备;如果可以,请使用真实的预处理语句!)

只有在您不能使用预准备语句的情况下才能考虑转义(动态生成的查询,LIMIT)。在这些特定情况下,请确保您不是making mysqli_real_escape_string() bypassable because of misconfigured character sets。 (ircmaxell的这个链接的StackOverflow答案比我更好地解释了这个问题。)

WordPress最近出现了一个问题,即多字节字符可以绕过他们的SQL转义策略the security team patched it under the guise of Emoji support

如果您正在使用mysql_real_escape_string()mysqli_real_escape_string(),那么您正在玩火。小心你不要被烧伤。