今天早些时候,有人询问有关网络应用中输入验证策略的问题.
在撰写本文时,最重要的答案建议PHP
只使用htmlspecialchars
和mysql_real_escape_string
.
我的问题是:这总是足够的吗?还有更多我们应该知道的吗?这些功能在哪里崩溃?
在数据库查询方面,请始终尝试使用准备好的参数化查询.在mysqli
和PDO
库支持这一点.这比使用转义函数更安全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 '';
我们已经在HTML标记内,因此我们不需要<或>做任何危险的事情.我们的攻击向量可能就是javascript:alert(document.cookie)
现在生成的HTML看起来像
攻击直接进行.
它变得更糟.为什么?因为htmlspecialchars
(以这种方式调用)只编码双引号而不是单引号.所以,如果我们有
echo "";
我们的邪恶攻击者现在可以注入全新的参数
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的方式.但是,您可以回退到更有限的编码,例如ISO-8859-1,直到IE6使用率下降.
有关多字节问题的更深入研究,请参阅/sf/ask/17360801/
除了Cheekysoft的优秀答案:
是的,他们会保证您的安全,但前提是他们的使用绝对正确.错误地使用它们仍然容易受到攻击,并且可能存在其他问题(例如数据损坏)
请改用参数化查询(如上所述).您可以通过PDO或PEAR DB之类的包装来使用它们
确保magic_quotes_gpc和magic_quotes_runtime始终处于关闭状态,并且永远不会被意外打开,甚至不会短暂打开.这些是PHP开发人员为防止安全问题(破坏数据)而进行的早期和深度误导的尝试
防止HTML注入(例如跨站点脚本)并没有真正的灵丹妙药,但如果您使用库或模板系统输出HTML,则可能更容易实现.阅读有关如何正确解决问题的文档.
在HTML中,需要根据上下文对事物进行不同的转义.对于放入Javascript的字符串尤其如此.