一尘不染

htmlspecialchars和mysql_real_escape_string是否可以防止我的PHP代码被注入?

php

今天早些时候,有人问了有关Web应用程序中输入验证策略的问题。

在撰写本文时,最高答案建议PHP仅使用htmlspecialcharsmysql_real_escape_string

我的问题是:这是否总是足够?还有更多我们应该知道的吗?这些功能在哪里分解?


阅读 456

收藏
2020-05-26

共1个答案

一尘不染

对于数据库查询,请始终尝试使用准备好的参数化查询。在mysqliPDO库支持这一点。这比使用转义功能(例如)更加安全mysql_real_escape_string

是的,mysql_real_escape_string实际上只是一个字符串转义功能。这不是魔术子弹。它所要做的就是逃避危险字符,以便可以安全地在单个查询字符串中使用它们。但是,如果您不事先清理输入内容,那么您将容易受到某些攻击媒介的攻击。

想象以下SQL:

$result = "SELECT fields FROM table WHERE id = ".mysql_real_escape_string($_POST['id']);

您应该能够看到这很容易被利用。
假设id参数包含公共攻击向量:

1 OR 1=1

那里没有危险的字符进行编码,因此它将直接通过转义过滤器。离开我们:

SELECT fields FROM table WHERE id= 1 OR 1=1

这是一个可爱的SQL注入向量,它将使攻击者可以返回所有行。要么

1 or is_admin=1 order by id limit 1

产生

SELECT fields FROM table WHERE id=1 or is_admin=1 order by id limit 1

在这个完全虚构的示例中,这使攻击者可以返回第一位管理员的详细信息。

这些功能虽然有用,但必须谨慎使用。您需要确保所有Web输入都经过一定程度的验证。在这种情况下,我们发现我们可以被利用,因为我们没有检查用作数字的变量实际上是数字。在PHP中,您应该广泛使用一组函数来检查输入是否为整数,浮点数,字母数字等。但是对于SQL,请注意准备好的语句的大部分值。如果上面的代码是预准备的语句,则它是安全的,因为数据库函数将知道这1 OR 1=1不是有效的文字。

至于htmlspecialchars()。那是它自己的雷区。

PHP中存在一个真正的问题,因为它具有与html相关的各种转义功能的全部选择,而对于确切的功能没有明确的指导。

首先,如果您位于HTML标记内,则确实会遇到麻烦。看着

echo '<img src= "' . htmlspecialchars($_GET['imagesrc']) . '" />';

我们已经在HTML标记中,因此我们不需要<或>做任何危险的事情。我们的攻击媒介可能就是javascript:alert(document.cookie)

现在结果HTML看起来像

<img src= "javascript:alert(document.cookie)" />

攻击直截了当。

情况变得更糟。为什么?因为htmlspecialchars(以这种方式调用)仅编码双引号而不是单引号。所以如果我们有

echo "<img src= '" . htmlspecialchars($_GET['imagesrc']) . ". />";

我们的邪恶攻击者现在可以注入全新的参数

pic.png' onclick='location.href=xxx' onmouseover='...

给我们

<img src='pic.png' onclick='location.href=xxx' onmouseover='...' />

在这些情况下,没有魔术的子弹,您只需要自己修改输入即可。如果尝试滤除不良字符,您肯定会失败。采取白名单方法,只允许通过一些好的字符。查看XSS备忘单,了解有关如何实现多种向量的示例

即使htmlspecialchars($string)在HTML标签之外使用,您仍然容易受到多字节字符集攻击向量的攻击。

您可能最有效的方法是使用mb_convert_encoding和htmlentities的组合,如下所示。

$str = mb_convert_encoding($str, 'UTF-8', 'UTF-8');
$str = htmlentities($str, ENT_QUOTES, 'UTF-8');

即使这样,由于IE6处理UTF的方式,它也容易受到攻击。但是,在IE6的使用率下降之前,您可能会使用较为有限的编码,例如ISO-8859-1。

2020-05-26