今天早些时候,有人问了有关Web应用程序中输入验证策略的问题。
在撰写本文时,最高答案建议PHP仅使用htmlspecialchars和mysql_real_escape_string。
PHP
htmlspecialchars
mysql_real_escape_string
我的问题是:这是否总是足够?还有更多我们应该知道的吗?这些功能在哪里分解?
对于数据库查询,请始终尝试使用准备好的参数化查询。在mysqli和PDO库支持这一点。这比使用转义功能(例如)更加安全mysql_real_escape_string。
mysqli
PDO
是的,mysql_real_escape_string实际上只是一个字符串转义功能。这不是魔术子弹。它所要做的就是逃避危险字符,以便可以安全地在单个查询字符串中使用它们。但是,如果您不事先清理输入内容,那么您将容易受到某些攻击媒介的攻击。
想象以下SQL:
$result = "SELECT fields FROM table WHERE id = ".mysql_real_escape_string($_POST['id']);
您应该能够看到这很容易被利用。 假设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()。那是它自己的雷区。
htmlspecialchars()
PHP中存在一个真正的问题,因为它具有与html相关的各种转义功能的全部选择,而对于确切的功能没有明确的指导。
首先,如果您位于HTML标记内,则确实会遇到麻烦。看着
echo '<img src= "' . htmlspecialchars($_GET['imagesrc']) . '" />';
我们已经在HTML标记中,因此我们不需要<或>做任何危险的事情。我们的攻击媒介可能就是javascript:alert(document.cookie)
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标签之外使用,您仍然容易受到多字节字符集攻击向量的攻击。
htmlspecialchars($string)
您可能最有效的方法是使用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。