今天早些时候,有人问到有关input validation strategies in web apps的问题。做htmlspecialchars和mysql_real_escape_string保持我的PHP代码安全注入?
在撰写本文时,顶部的答案建议在PHP
只使用htmlspecialchars
和mysql_real_escape_string
。
我的问题是:这足够吗?我们应该知道更多吗?这些功能在哪里分解?
今天早些时候,有人问到有关input validation strategies in web apps的问题。做htmlspecialchars和mysql_real_escape_string保持我的PHP代码安全注入?
在撰写本文时,顶部的答案建议在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
,允许攻击者在这个完全虚构的例子返回第一个管理员的详细信息。
虽然这些功能很有用,但必须小心使用。您需要确保所有网页输入在某种程度上得到验证。在这种情况下,我们看到我们可以被利用,因为我们没有检查我们用作数字的变量,实际上是数字。在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 cheat sheet,了解各种向量可能的示例
即使您在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。
为了更深入的研究,多字节的问题,请参见https://stackoverflow.com/a/12118602/1820
除了Cheekysoft的出色答卷:
是不是真的为了防止HTML注入(如跨站脚本)银弹,但你可以如果您使用库或模板系统输出HTML,则可以更轻松地实现它。阅读有关如何正确转义事物的文档。
在HTML中,事情需要根据上下文以不同的方式转义。对于放入Javascript的字符串尤其如此。
我肯定会与上述职位同意,但我有一个小的事情在回答增加Cheekysoft的回答,特别是:
当涉及到数据库查询, 总是试图用准备 参数化查询。 mysqli和PDO库支持这一点。这是 比使用转义 功能如 mysql_real_escape_string更安全。
是的,mysql_real_escape_string是 有效只是一个字符串转义 函数。这不是一个神奇的子弹。 它会做的只是逃脱危险 字符,以便它们可以安全地在单个查询字符串中使用 。 但是,如果您没有事先对您的 输入进行消毒,那么您将成为 容易受到某些攻击媒介的攻击。
想象以下SQL:
$结果= “选择FROM表 字段WHERE ID = ” .mysql_real_escape_string($ _ POST [ 'ID']);
您应该能够看到这是易受攻击的 。试想ID 参数包含了常见的攻击向量 :
1 OR 1 = 1
那里面有没有风险的字符来 编码,因此它会直接 通过逃避过滤器。离开 我们:
选择字段FROM表WHERE ID = 1 OR 1 = 1
我编写了一个小巧的功能,我把我的数据库类,将去掉任何心不是一个数量。它使用了preg_replace,所以概率更优化的一点作用,但在紧要关头的作品...
function Numbers($input) {
$input = preg_replace("/[^0-9]/","", $input);
if($input == '') $input = 0;
return $input;
}
因此,而不是使用
$结果=“选择字段FROM表WHERE ID =“.mysqlrealescapestring(”1 OR 1 = 1“);
我会用
$结果= “选择字段FROM表WHERE ID =”。数字(“1或1 = 1”);
,它会安全地运行查询从表
选择字段WHERE ID = 111
当然,这只是停止了它无法显示正确的行,但我不认为是谁试图注入到您的网站的SQL是一个大问题;)
这个难题的一个重要部分是上下文。
SELECT fields FROM table WHERE id='".mysql_real_escape_string($_GET['id'])."'"
导致:
SELECT fields FROM table WHERE id='1 OR 1=1'
这是无效的,如果你在引用查询的每个论点有人发送 “1 OR 1 = 1” 的ID是没有问题的。由于您正在转义字符串,所以输入无法脱离字符串上下文。我已经测试过MySQL的版本5.0.45,并且使用整数列的字符串上下文不会导致任何问题。
$result = "SELECT fields FROM table WHERE id = ".(INT) $_GET['id'];
在64位系统上工作良好,甚至更好。尽管如此,请注意您的系统在处理大量数据时的限制,但对于数据库ID来说,这在99%的时间内很有效。
您应该使用单个函数/方法来清理您的值。即使这个函数只是mysql_real_escape_string()的包装器。为什么?因为有一天,如果发现利用您的首选清理数据的方法,您只需将其更新到一个地方,而不是在系统范围内找到并替换。
为什么,哦为什么,你会而不是包括用户输入在您的SQL语句周围引号?似乎很愚蠢的不!包括你的sql语句中的引号会使“1或1 = 1”成为毫无结果的尝试,不是吗?
所以现在,你会说,“如果用户在输入中包含引号(或双引号)会怎么样?”
好吧,简单的解决方法:只需删除用户输入的报价。例如:。现在,无论如何,在我看来,用户输入将是安全的...
这里唯一遗漏的是,DB查询的第一个例子...一个简单的intval()将解决注入。需要数字而不是字符串时,始终使用intval()代替mysqlescape ...()。 – 2009-04-09 03:15:58
并记住使用参数化查询将允许您始终将数据视为数据而不是代码。尽可能使用PDO等库并使用参数化查询。 – Cheekysoft 2009-04-14 10:47:37
优秀的答案! – joedevon 2009-06-12 07:06:02