今天早些时候,有人问了一个关于input validation strategies in web apps的问题.
在 compose 本文时,最重要的答案是建议在PHP
中只使用htmlspecialchars
和mysql_real_escape_string
.
我的问题是:这总是足够吗?还有更多我们应该知道的吗?这些功能在哪里失效?
今天早些时候,有人问了一个关于input validation strategies in web apps的问题.
在 compose 本文时,最重要的答案是建议在PHP
中只使用htmlspecialchars
和mysql_real_escape_string
.
我的问题是:这总是足够吗?还有更多我们应该知道的吗?这些功能在哪里失效?
当涉及到数据库查询时,总是try 使用预先准备好的参数化查询.mysqli
和PDO
个库支持这一点.这比使用转义函数(如mysql_real_escape_string
)安全得多.
是的,mysql_real_escape_string
实际上只是一个字符串转义函数.这不是一颗神奇的子弹.它所做的一切就是对危险字符进行转义,以便在单个查询字符串中可以安全地使用这些字符.但是,如果您不事先清理您的输入,那么您将容易受到某些攻击媒介的攻击.
想象一下下面的SQL:
$result = "SELECT fields FROM table WHERE id = ".mysql_real_escape_string($_POST['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相关转义函数可供 Select ,但对于哪些函数做什么没有明确的指导.
首先,如果你在一个HTML标签中,你会遇到真正的麻烦.看看
echo '<img src= "' . htmlspecialchars($_GET['imagesrc']) . '" />';
We're already inside an HTML tag, so we don't need < or > to do anything dangerous. Our attack vector could just be 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 cheat sheet个示例,了解向量的多样性
即使使用htmlspecialchars($string)
个HTML标记之外的标记,也仍然容易受到多字节字符集攻击向量的攻击.
最有效的方法是结合使用mb_convert_编码和htmlentities,如下所示.
$str = mb_convert_encoding($str, 'UTF-8', 'UTF-8');
$str = htmlentities($str, ENT_QUOTES, 'UTF-8');
即使这样,IE6也很脆弱,因为它处理UTF的方式.然而,在IE6使用率下降之前,您可以退回到更有限的编码方式,如ISO-8859-1.
有关多字节问题的更深入研究,请参见https://stackoverflow.com/a/12118602/1820