mysql_real_escape_string的缺点?

时间:2012-10-03 07:02:48

标签: php mysql sql-injection mysql-real-escape-string

我在这里看到一些人说使用mysql_real_escape_string连接查询不能保护你(完全)免受SQL注入攻击。

但是,我还没有看到一个输入示例,说明了mysql_real_escape_string无法保护你的攻击。大多数示例都忘记了mysql_query仅限于一个查询并错误地使用mysql_real_escape_string

我能想到的唯一例子是:

mysql_query('DELETE FROM users WHERE user_id = '.mysql_real_escape_string($input));

这不会保护您免受以下输入:

5 OR 1=1

我认为这是mysql_real_escape_string的错误用法而不是缺点,它是为字符串而非数值设计的。您应该转换为数字类型,或者如果要在清理时将输入视为字符串,则应在查询中执行相同的操作并在其周围加上引号。

任何人都可以提供一个可以绕过mysql_real_escape_string而不依赖于错误处理数值的输入示例,或者忘记mysql_query只能执行一个查询吗?

编辑:我对mysql_real_escape_string的限制感兴趣,而不是将其与替代品进行比较,我意识到新项目有更好的选择,我并不反对。

2 个答案:

答案 0 :(得分:6)

mysql_real_escape_string或mysql_扩展的主要缺点是,它比其他更现代的API(尤其是预处理语句)更难以正确应用。 mysql_real_escape_string应该只用于一种情况:转义文本内容,用作引号之间的SQL语句中的值。 E.g:

$value = mysql_real_escape_string($value, $link);
$sql = "... `foo` = '$value' ...";
                     ^^^^^^

mysql_real_escape_string确保上述上下文中的$value不会弄乱SQL语法。它没有像你想象的那样工作:

$sql = "... `foo` = $value ...";

或在这里:

$sql = "... `$value` ...";

或在这里:

$sql = mysql_real_escape_string("... `foo` = '$value' ...");

如果应用于在SQL语句中除了带引号的字符串之外的任何上下文中使用的值,它将被误用,可能会或可能不会弄乱结果语法和/或允许某人提交可能启用SQL注入攻击的值。 mysql_real_escape_string的用例非常狭窄,但很少被正确理解。

使用mysql_real_escape_string让自己陷入热水的另一种方法是使用错误的方法设置数据库连接编码。你应该这样做:

mysql_set_charset('utf8', $link);

可以也这样做:

mysql_query("SET NAMES 'utf8'", $link);

问题是后者绕过mysql_ API,它仍然认为你正在使用latin1(或其他东西)与数据库交谈。现在使用mysql_real_escape_string时,它将采用不同的字符编码和转义字符串,而不是数据库稍后会解释它们。通过运行SET NAMES查询,您已经创建了mysql_客户端API如何处理字符串以及数据库将如何解释这些字符串之间的裂痕。这可以用于某些多字节字符串情况下的注入攻击。

mysql_real_escape_string中没有基本的注入漏洞,如果正确应用,我知道然而,主要的问题是,错误地应用它是非常容易的,这会打开漏洞。

答案 1 :(得分:0)

好的,除了mysql_*被弃用之外,我了解您希望了解可能存在的任何可能的解决方法。 perhaps this blog post并且幻灯片可能会显示其中的一部分。
但正如this older question所示,投射和引用并非完全证明。只有许多可能出错的东西,墨菲的法律与那个曾经有效的口头禅“永远不会信任网络”纠缠在一起,将会出现可怕的错误。

或许this article,但最重要的是,the follow-up to that article可以揭示更多安全问题。说实话,我知道mysql_real_escape_string不是全面的,即使与类型转换和字符串格式相结合:

printf('WHERE id = \'%d\'',(int)mysql_real_escape_string($_REQUEST['id']));

并未涵盖所有可能的攻击。我不是这方面的专家,但我可以告诉你的是清理每一个输入,如果有的话,会给你一个 FALSE 的安全感。大多数时候,你会(最初)知道什么,为什么以及如何防范攻击,但你的同事可能不会。他们可能会忘记某些事情,并且整个系统都会受到损害。

总结:是的,您可以阻止任何形式的恶意输入进入您的数据库,但它所需的每一个额外操作都会增加风险。在那种情况下,最大的责任(一如既往)是开发人员没有在星期一早上喝第四杯咖啡。没有任何代码,无论多么具有防守性和深思熟虑,都可以保护自己免受那个厌倦了脾气暴躁的开发者的怪物的影响,对咖啡因和尼古丁感冒。