mysqli_real_escape_string 易受攻击

Posted

技术标签:

【中文标题】mysqli_real_escape_string 易受攻击【英文标题】:Mysqli_real_escape_string vulnerable 【发布时间】:2018-11-17 04:52:45 【问题描述】:

所以我忙于 php,当我想知道时将数据插入 mysql:我遇到一些帖子说使用单引号将数据插入数据库是不好的做法。示例之一:Why are VALUES written between quotes when sent to a database? 这篇文章是关于为什么它们被写在引号之间,但有一点很清楚:插入它是不好的做法:

$sql = INSERT INTO example (example1, example2, example3) VALUES 
('$example1', '$example2', '$example3');

为什么这是不好的做法?显然,如上面给出的链接中所述,注入是易受攻击的。 OP 他的问题与评论有关:我们为此使用mysqli_real_escape_string。给出的答案是:

@XX 在很大程度上,是的,它是解决问题的替代方案。它不会禁用任何东西,但它会转义一些东西,例如 SQL 字符串中的 ' 变成 '' 或 \' ,从而阻止攻击者结束字符串。在一些尴尬的情况下,这种转义很难,而且很容易错过许多转义调用,这就是为什么参数化查询被认为是最可靠的方法。

首先:脚本如何欺骗mysqli_real_escape_string 使其不转义某些内容?我发现了以下内容,如果我错了,请纠正我:mysqli_real_escape_string - example for 100% safety。如您所见,他指的是另一个页面,该页面有答案。然而,他随后声称应该使他的数据 100% 安全,而其他人则回应:

是的,这通常是安全的。正确使用时,Mysql 和 mysqli 是完全安全的(尽管在非常特定的编码中存在特定的错误)。准备好的语句的优点是更难以错误的方式做事。

我有下面的例子让我自己清楚:我有 2 扇门,1 扇门是开着的,但在一扇紧闭的门后面。你会如何攻击前面有一扇门关着的敞开的门?

这里有一个答案:SQL injection that gets around mysql_real_escape_string(),但他说作为一个安全的例子:

mysql_query('SET NAMES utf8');
$var = mysql_real_escape_string("\xbf\x27 OR 1=1 /*");
mysql_query("SELECT * FROM test WHERE name = '$var' LIMIT 1");`

mysqli_real_escape_string 不是已经在做同样的事情了吗?他只是指定哪些字符应该是mysqli_real_escaped_string。那么这一切怎么会突然变得安全呢?因为它做的事情和你说的完全一样:

$example = mysqli_real_escape_string ($conn, $_POST['exampleVariable']);

那么这是怎么做到的:

mysql_query('SET NAMES utf8');
$var = mysql_real_escape_string("\xbf\x27 OR 1=1 /*");
mysql_query("SELECT * FROM test WHERE name = '$var' LIMIT 1");

变得安全,这样:

$example = mysqli_real_escape_string ($conn, $_POST['exampleVariable']);

不是吗?他不是只是缩小了mysqli_real_escape_string 会逃脱的范围,从而使其更容易受到攻击吗?

【问题讨论】:

请阅读此内容以获取更多信息:***.com/questions/12859942/… 顺便说一句,我认为这个问题根本不是所引用的问题的重复。这个问题询问的是手动转义而不是参数化查询,这与一般不推荐使用的功能无关,所以我将其标记为重新打开。 确实,这不是为什么你不应该使用 mysql-functions 问题的重复。我附议重新开放。 【参考方案1】:

问题是,mysqli_real_escape_string() 或其他适当的转义实际上在技术上是安全的,最后,这也是参数化查询所做的事情。然而,总有一个然而。例如,只有在变量周围有引号时它才是安全的。没有引号就不是。当它是一个开发人员的 1000 行项目时,前 3 个月可能还可以。然后最终即使是一位开发人员也会忘记引号,因为在语法上并不总是需要它们。想象一下 200 名开发人员的 200 万个 LOC 项目在 5 年后会发生什么。

同样,您决不能忘记使用手动转义功能。首先可能很容易。然后有一个变量是经过验证的,只能保存一个数字,所以你确定直接把它放进去而不转义就可以了。然后你改变主意,把它变成一个字符串,因为无论如何查询都可以。或者其他人在2年后这样做。等等。这不是技术问题。这是一个管理问题,从长远来看,您的代码会以某种方式受到攻击。因此,这是不好的做法。

另外一点,如果有手动转义,自动扫描 SQL 注入漏洞会更加困难。静态代码扫描器可以轻松找到串联查询的所有实例,但它们很难关联以前的转义(如果有的话)。如果你使用参数化查询之类的东西,很容易找到 sql 注入,因为所有连接都是潜在的候选者。

【讨论】:

【参考方案2】:

为连接设置字符集不会改变mysqli_real_escape_string() 的转义。但是它避免了多字节字符错误,因为它控制了在插入反斜杠转义字符后如何解释字符串。

当然,您可以通过using query parameters instead 避免任何不确定性。

【讨论】:

以上是关于mysqli_real_escape_string 易受攻击的主要内容,如果未能解决你的问题,请参考以下文章

“mysqli_real_escape_string”是不是足以避免 SQL 注入或其他 SQL 攻击?

mysqli_real_escape_string 如何无法阻止 SQL 注入? [复制]

mysqli_real_escape_string 如何无法阻止 SQL 注入? [复制]

filter_var 或 mysqli_real_escape_string [重复]

带单引号的 Mysqli_real_escape_string - 安全吗? [复制]

带单引号的 Mysqli_real_escape_string - 安全吗? [复制]