【问题标题】:mysql_escape_string vulnerabilitiesmysql_escape_string 漏洞
【发布时间】:2012-10-13 03:36:40
【问题描述】:

我最近在向我的朋友解释参数化及其优点,他问它在安全性方面比 mysqli_escape_string 好多少。具体来说,您能想到任何 SQL 注入示例,尽管输入字符串被转义(使用 mysqli_escape_string),但仍会成功?

更新:

对于我最初的问题不够清楚,我深表歉意。这里提出的一般问题是,尽管转义输入字符串,SQL 注入是否可能?

【问题讨论】:

  • 来自手册: > 自 PHP 5.3.0 起,该函数已被弃用。强烈建议不要依赖此 > 功能。不要在已弃用的代码上投入精力。使用参数绑定,不用担心SQL注入。
  • 请不要使用mysql_* 函数编写新代码。它们不再维护,社区已经开始deprecation process。看到red box?相反,您应该了解prepared statements 并使用PDOMySQLi。如果你不能决定哪一个,this article 会帮助你。如果你选择 PDO,here is good tutorial。另见Why shouldn't I use mysql functions in PHP?
  • 这个我已经知道了,我不提倡使用mysql扩展。我只是要求您说明如何它是易受攻击的。
  • 这是因为它被替换为mysqli_real_escape_string(),而不是因为你不应该再转义字符串了。
  • @martinstoeckli:这种变化也对答案产生了影响:)

标签: php mysql sql-parametrized-query


【解决方案1】:

更新答案

这个问题被编辑(在我的答案发布后)专门针对mysqli_escape_string,它是mysql_real_escape_string 的别名,因此考虑了连接编码。这使得原始答案不再适用,但为了完整起见,我将其保留。

新答案,简而言之:mysqli_escape_string 在安全方面与参数化查询一样好,前提是您不会自爆

具体来说,PHP doc page 上的巨大警告中突出显示了你不能做的事情:

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

如果您不注意此警告(即,如果您使用直接 SET NAMES 查询更改字符集)并且您将字符集从单字节编码更改为“方便"(从攻击者的角度来看)多字节编码,你实际上会模仿愚蠢的mysql_escape_string 所做的:尝试在不知道输入的编码的情况下转义字符。

这种情况使您可能容易受到 SQL 注入的攻击,如下面的原始答案所述。

重要提示:我记得在某处读到过,最近的 MySql 版本已经堵住了这个漏洞(在客户端库中?),这意味着您可能是完美的即使使用SET NAMES 切换到易受攻击的多字节编码也是安全的。但请不要相信我的话。

原答案

相对于mysql_real_escape_string,裸mysql_escape_string没有考虑connection encoding。这意味着它假设输入是单字节编码,而实际上它可以合法地采用多字节编码。

一些多字节编码具有对应于单个字符的字节序列,其中一个字节是单引号的 ASCII 值 (0x27);如果输入这样的字符串,mysql_escape_string 会很高兴地“转义引号”,这意味着用 0x5c 0x27 替换 0x27。根据编码规则,这可能会导致将多字节字符变为另一个包含0x5c 的字符,并将“剩余”0x27 作为输入中的独立单引号。瞧,您在 SQL 中注入了一个未转义的引号。

更多详情请见this blog post

【讨论】:

  • +1 几乎是唯一的主题回答者。一定是被否决了,因为您没有在答案中以粗体大写字母高度不鼓励
  • @Asad:你特别没有要求那样的东西,所以我想这是你的错:)
  • 我专门询问了使用 mysql_escape_string 时如何发生 SQL 注入的示例。这得到了我的问题提出Specifically, can you think of any examples of SQL injection that would succeed despite the input strings being escaped的事实的支持
【解决方案2】:

不好的答案:

具体来说,你能想到任何 SQL 注入的例子吗? 尽管输入字符串被转义(使用 mysql_escape_string)?

不可靠。您指的是mysql_escape_string(),它不考虑连接编码(而mysql_real_escape_string() 考虑)。

所以也许一个精心制作的字符串,前面有一个精心制作的不完整 UTF8 代码点,可能导致,比如说,mysql_escape_string() 转义引号 但转义本身是被 MySQL 忽略,因为它会将其“视为”为 UTF8 字符。

例如:

0xC2' OR 1=1 ;--

将被mysql_escape_string() 转义为

0xC2\' OR 1=1 ;--

将被组装到

WHERE password='0xC2\' OR 1=1 ;--';

并被 MySQL 视为(如果正确的连接编码生效),例如,

WHERE password='€' OR 1=1 ;[--';]    <-- the bracketed part is considered a comment and ignored

这将是一个经典的 SQL 注入。

但这取决于您指定的事实,可能是通过分心,双重弃用功能。如果你真的指的是mysql_real_escape_string(),那就不行了。

此外,这假定服务器和应用程序层(例如 PHP)在填充输入时都没有使用任何类型的字符集验证。如果他们这样做了,无效的 UTF8 将在到达时被删除,甚至不会被 mysql_escape_string 看到,那当然就足够了。

真正的答案:

根本不要使用mysql_escape_string(或mysql_whatever)。它们已被弃用,您的代码可能会停止工作。请改用 PDO 函数。

【讨论】:

  • 不,它会被组装到WHERE password='0xC2\' OR 1=1 ;--\'';
猜你喜欢
  • 1970-01-01
  • 2021-06-05
  • 2017-06-08
  • 1970-01-01
  • 2023-04-07
  • 1970-01-01
  • 1970-01-01
  • 2022-01-12
  • 2012-08-16
相关资源
最近更新 更多