Mysqli_real_escape_string 脆弱

Mysqli_real_escape_string vulnerable

所以我忙于 PHP,在我想知道的时候将数据插入 mysql:我遇到了一些 post 说使用单引号是不好的做法将数据插入数据库。示例之一: post 是关于为什么将它们写在引号之间,但有一点很清楚:像这样插入它是不好的做法:

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

为什么这是不好的做法?显然,按照上面给出的 link 进行注入是很容易的。他的问题与评论相关的 OP 是:我们为此使用 mysqli_real_escape_string。给出的回复是:

@XX To a large extent, yes, it is an alternative solution to the problem. It doesn't disable anything, but it escapes things so that for instance ' becomes '' or \' in the SQL string, keeping the attacker from ending the string. There are awkward cases where such escaping is hard, and it's easy to miss one escape call among many, which is why parametrised queries are considered the most reliable approach.

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

Yes, that is generally safe. Mysql and mysqli are perfectly safe when used right (specific bugs in very specific encodings notwithstanding). The advantage of prepared statements is that it's more difficult to do things the wrong way.

我用下面的例子来说明一下:我有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 可以逃脱的范围,从而使其更容易受到攻击吗?

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

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

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

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

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