2008-09-21 65 views

回答

227

当涉及到数据库查询时,总是尝试使用准备好的参数化查询。 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 

,允许攻击者在这个完全虚构的例子返回第一个管理员的详细信息。

虽然这些功能很有用,但必须小心使用。您需要确保所有网页输入在某种程度上得到验证。在这种情况下,我们看到我们可以被利用,因为我们没有检查我们用作数字的变量,实际上是数字。在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

+23

这里唯一遗漏的是,DB查询的第一个例子...一个简单的intval()将解决注入。需要数字而不是字符串时,始终使用intval()代替mysqlescape ...()。 – 2009-04-09 03:15:58

+10

并记住使用参数化查询将允许您始终将数据视为数据而不是代码。尽可能使用PDO等库并使用参数化查询。 – Cheekysoft 2009-04-14 10:47:37

+1

优秀的答案! – joedevon 2009-06-12 07:06:02

9

除了Cheekysoft的出色答卷:

  • 是的,他们会保证你的安全,但前提是要使用它们绝对正确。错误地使用它们,你仍然会很脆弱,并且可能还有其他问题(例如数据损坏)
  • 请改用参数化查询(如上所述)。您可以通过例如PDO或通过包装PEAR DB
  • 请确保magic_quotes_gpc和magic_quotes_runtime始终处​​于关闭状态,并且永远不会意外打开,甚至不会短暂地打开。这是由PHP的开发早期和深度误导试图阻止安全问题(它破坏数据)

是不是真的为了防止HTML注入(如跨站脚本)银弹,但你可以如果您使用库或模板系统输出HTML,则可以更轻松地实现它。阅读有关如何正确转义事物的文档。

在HTML中,事情需要根据上下文以不同的方式转义。对于放入Javascript的字符串尤其如此。

3

我肯定会与上述职位同意,但我有一个小的事情在回答增加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是一个大问题;)

2

这个难题的一个重要部分是上下文。

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,并且使用整数列的字符串上下文不会导致任何问题。

1
$result = "SELECT fields FROM table WHERE id = ".(INT) $_GET['id']; 

在64位系统上工作良好,甚至更好。尽管如此,请注意您的系统在处理大量数据时的限制,但对于数据库ID来说,这在99%的时间内很有效。

您应该使用单个函数/方法来清理您的值。即使这个函数只是mysql_real_escape_string()的包装器。为什么?因为有一天,如果发现利用您的首选清理数据的方法,您只需将其更新到一个地方,而不是在系统范围内找到并替换。

-3

为什么,哦为什么,你会而不是包括用户输入在您的SQL语句周围引号?似乎很愚蠢的不!包括你的sql语句中的引号会使“1或1 = 1”成为毫无结果的尝试,不是吗?

所以现在,你会说,“如果用户在输入中包含引号(或双引号)会怎么样?”

好吧,简单的解决方法:只需删除用户输入的报价。例如:。现在,无论如何,在我看来,用户输入将是安全的...