我有这样的代码:
$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
做些什么才能使这段代码安全?在我的情况下,我不建立任何数据库连接。
答案 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)上运行,只需 你需要的东西确保是:
$myvar
不包含任何斜杠("/"
,U + 002F)或null("\0"
,U + 0000)字符,
$myvar
不为空或等于"."
(或等效地,".$myvar"
不等于"."
或".."
)。
那是因为,在Unix文件系统上,唯一的目录分隔符(以及文件名中不允许的两个字符之一,另一个是空字符"\0"
)是斜杠,也是唯一的特殊目录条目向上指向目录树的是"."
和".."
。
但是,如果您的代码有一天可能会在Windows上运行,那么您将需要禁止更多字符(至少反斜杠,"\\"
,以及可能还有其他字符)。我对Windows文件系统惯例不够熟悉,无法确切地说明你需要禁用哪些字符,但安全方法只能as Rich Bradshaw suggests和 >允许您知道的字符是安全的。
答案 3 :(得分:1)
与来自不受信任来源的每个数据一样:在使用前验证它并在将其传递到另一个上下文时对其进行正确编码。
对于前者,您首先需要指定数据必须具有哪些属性才能被视为有效。这主要取决于其使用目的。
在您的情况下,$myvar
的值应该至少应该是有效的目录名,但它也可以是由目录名组成的有效相对路径,具体取决于您的要求。此时,您应该指定这些要求。