读取通过$ _GET提供的文件

时间:2010-06-08 13:18:30

标签: php security

我有一个php脚本,它通过$_GET获取相对路径名,读取该文件并创建它的缩略图。我不希望用户能够从服务器读取任何文件。只允许来自某个目录的文件,否则脚本应为exit()

这是我的文件夹结构:

files/ <-- all files from this folder are public
my_stuff/ <-- this is the folder of my script that reads the files

我的脚本可通过mydomain.com/my_stuff/script.php?pathname=files/some.jpg访问。什么不应该被允许e。 g。:mydomain.com/my_stuff/script.php?pathname=files/../db_login.php

所以,这是my_stuff文件夹中脚本的相关部分:

...
$pathname = $_GET['pathname'];
$pathname = realpath('../' . $_GET['pathname']); 

if(strpos($pathname, '/files/') === false) exit('Error');
...

我对这种方法不太确定,对我来说似乎不太安全。谁有更好的主意?

5 个答案:

答案 0 :(得分:3)

我先做realpath()(解析任何“../”和其他引用),然后检查结果是否是允许的子目录。

采取你的场景(我不明白为什么你需要使用文件/在这种情况下,如果它是唯一允许的目录,但无论如何):

$basedir = "/etc/www"; 
$allowed = "/etc/www/files";

$pathname = realpath($basedir."/".$_GET["pathname"]);

if (!$pathname) 
 die ("Unknown file path");

// Check whether $pathname begins with $allowed (= is a sub-directory)
if (substring($pathname, 0, strlen($allowed)) != $allowed)
 die ("illegal access!");

据我所知,这应该是一种安全的方法。

答案 1 :(得分:2)

这个怎么样(它处理移动服务器的情况,因为没有硬编码的绝对路径):

$pathname = realpath('../' . $_GET['pathname']);
$rootpath = realpath('../files/');

if (strpos($pathname, $rootpath) !== 0) exit('Error');

答案 2 :(得分:0)

我曾经这样做过一次 basedir被定义为脚本所在的目录。

$basedir=dirname(__FILE__)."/";
$systemdir=realpath($_SERVER['DOCUMENT_ROOT'].$dir)."/";
if (substr($systemdir,0,strlen($basedir)) !== $basedir) {

......但是佩卡更快:)

答案 3 :(得分:0)

我还会检查./中是否存在../$_GET['pathname'],因为这样做几乎是一个他们不应该去的地方。确实realpath使其安全(因为...已“解决”),但strpos检查在某些(可能是错误的)情况下可能很弱/files/字符串稍后出现但在访问实际文件时会被忽略,例如像

这样的假设技​​巧
/site/my_stuf/secretfile.txt /files/

(使用这样的字符串来访问文件应该“看到”“secretfile.txt”(包含空格)不是dir名称,一切都应该失败......但正如所说,这个假设可能是真正的一个错误场景,如果技巧利用其他一些不那么假设的错误...当然不知道它被利用了吗?

所以我特别重复我的建议,检查GET字符串中的../;并且,为什么不将此字符串解释为从files开始的路径,即将files/添加到用户提供的内容中,并避免已经说过../的存在?

我不知道所有这些是否是偏执的(或更好的解决方案存在),但我对基于url的目录/文件列表器使用了类似的方法,它允许“直接”访问我的站点的子目录,我当然希望确保没有办法逃离该目录。

答案 4 :(得分:0)

NB。使用realpath提供的答案是可以的,但是他们应该提到realpath在所有服务器变体中都不起作用。