安全地处理$ _GET PHP

时间:2012-03-18 14:38:04

标签: php security get

我有这样的代码:

$myvar=$_GET['var'];

// a bunch of code without any connection to DB where $myvar is used like this:

$local_directory=dirname(__FILE__).'/images/'.$myvar;
if ($myvar && $handle = opendir($local_directory)) {
    $i=0; 
    while (false !== ($entry = readdir($handle))) {
        if(strstr($entry, 'sample_'.$language.'-'.$type)) {
            $result[$i]=$entry;
            $i++;
        }
    } 
    closedir($handle);
} else {
    echo 'error';
}

我对一些剥离和转义函数有点困惑,所以问题是,我需要对$myvar做些什么才能使这段代码安全?在我的情况下,我不建立任何数据库连接。

4 个答案:

答案 0 :(得分:5)

您正在尝试阻止目录遍历攻击,因此您不希望此人放入./../../../或其他内容,希望根据您正在执行的操作来读取文件或文件名。

我经常使用这样的东西:

$myvar =  preg_replace("/[^a-zA-Z0-9-]/","",$_GET['var']);

这会将任何非a-zA-Z0-9-的内容替换为空白,因此如果变量包含say *,则此代码会删除该内容。

然后我改变a-zA-Z0-9-以匹配我想在字符串中允许的字符。然后,我可以将其锁定为仅包含数字或我需要的任何内容。

答案 1 :(得分:3)

执行以下操作非常非常危险:opendir($local_directory)其中$local_directory是一个可能来自外部的值。

如果有人传递../../../../../../../../../etc之类的东西......或类似的东西怎么办?您可能会损害主机的安全性。

你可以在这里看一眼,开始: http://php.net/manual/en/book.filter.php

恕我直言,如果你没有动态创建任何东西,你应该有类似的东西:

$allowed_dirs = array('dir1','dir2', 'dir3');
if (!in_array($myvar, $allowed_dirs)) {
    // throw an error and log what has happened
}

您可以在收到“外部”输入后立即执行此操作。如果您这样做是不切实际的,因为图像目标的数量会随着时间的推移而变化,并且您害怕错过与代码库的同步,您还可以填充有效值数组,以便扫描您拥有的子目录到图像中文件夹优先。

所以,最后,你可以有类似的东西:

$allowed_dirs = array();
if ($handle = opendir(dirname(__FILE__) . '/images')) {
    while (false !== ($entry = readdir($handle))) {
            $allowed_dirs[] = $entry;
    } 
    closedir($handle);
}
$myvar=$_GET['var'];

// you can deny access to dirs you want to protect like this
unset($allowed_dirs['private_stuff']);

// rest of code
$local_directory = dirname(__FILE__) . "/images/.$myvar";
if (in_array(".$myvar", $allowed_dirs) && $handle = opendir($local_directory)) {
    $i=0; 
    while (false !== ($entry = readdir($handle))) {
        if(strstr($entry, 'sample_'.$language.'-'.$type)) {
            $result[$i]=$entry;
            $i++;
        }
    } 
    closedir($handle);
} else {
    echo 'error';
}

上面的代码未经过优化。但是,让我们避免在这种情况下过早优化(说明这是为了避免另一个“好”的downvote);片段只是为了让你明确允许值的想法VS替代方法允许一切,除非匹配某个模式。我认为前者更安全。

答案 2 :(得分:2)

我要注意完整性, if 你可以确定你的代码只能在Unixish系统(例如Linux)上运行,只需 你需要的东西确保是:

  1. $myvar不包含任何斜杠("/",U + 002F)或null("\0",U + 0000)字符,

  2. $myvar不为空或等于"."(或等效地,".$myvar"不等于".""..")。

  3. 那是因为,在Unix文件系统上,唯一的目录分隔符(以及文件名中不允许的两个字符之一,另一个是空字符"\0")是斜杠,也是唯一的特殊目录条目向上指向目录树的是"."".."

    但是,如果您的代码有一天可能会在Windows上运行,那么您将需要禁止更多字符(至少反斜杠,"\\",以及可能还有其他字符)。我对Windows文件系统惯例不够熟悉,无法确切地说明你需要禁用哪些字符,但安全方法只能as Rich Bradshaw suggests >允许您知道的字符是安全的。

答案 3 :(得分:1)

与来自不受信任来源的每个数据一样:在使用前验证它并在将其传递到另一个上下文时对其进行正确编码。

对于前者,您首先需要指定数据必须具有哪些属性才能被视为有效。这主要取决于其使用目的。

在您的情况下,$myvar的值应该至少应该是有效的目录名,但它也可以是由目录名组成的有效相对路径,具体取决于您的要求。此时,您应该指定这些要求。