此PHP函数是否可以防止文件遍历? [英] Does this PHP function protect against file traversal?

查看:102
本文介绍了此PHP函数是否可以防止文件遍历?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个URL,它将为用户提供受保护的文件。



上载文件时,无论其名称如何,文件名都由我的应用程序重写,并存储在数据库中。所以我知道它永远不会包含 /或 ..。



文件名是: USER_ID _ RANDOMMD5。FILE_EXT
USER_ID =当前登录的用户ID和 RANDOM MD5。



ie 5_ji3uc237uckj92d0jf3932t09ut93f2.pdf



这是我提供文件的功能:

 功能user_file($ file_name =)
{
if($ file_name)
{
//确保没有有趣的公司名称:
$ file_name = str_replace( '..','',$ file_name);
$ file_name = str_replace( /,,$ file_name);

//检查是否允许用户访问该文件
$ user_id = substr($ file_name,0,strpos($ file_name, _));

//现在执行逻辑以检查用户是否已登录,并且用户是文件
的所有者(($ this-> ion_auth-> logged_in())&& ((($ user_id === $ this-> user-> id))
{
//通过readfile()服务文件
}
}
}

问题:这是确保没有问题的安全方法吗?

edit 1 :ion_auth是我的身份验证库,而 $ this-> user-> id是存储在我的结构中的用户ID



编辑2:用户文件存储在public_html外部-并且因此,只能通过我的应用程序AFAIK进行访问



编辑3:我的改进代码使用了以下Amber的想法,并考虑了我需要的事实适应不同的文件扩展名,我将尝试避免数据库命中:

 函数user_files($ file_name =)
{
//出于安全原因,请检查文件名是否正确
//检查32位md5值,后跟单个。,然后是3-4个扩展名(仅z),
if(preg_match('^ [A-Za-z0-9] {32} + [。] {1} [A-Za-z] {3,4} $ ^',$ file_name))
{
//现在检查用户已登录
if($ this-> ion_auth-> logged_in())
{
//将请求重写到服务器上的路径-并将user_id附加到文件名
/ /这可以确保用户只能访问自己上传的文件
//由于在上传过程中将userid附加到文件名中!
$ file = MY_SECURE_FOLDER。$ this->用户-> id 。’_’。$ file_name;

//现在检查文件是否存在
if(file_exists($ file))
{
//提供文件
标头('Content-类型:。get_mime_by_extension($ file));
readfile($ file);
}
}
}
}


解决方案

更好的主意:让用户提供MD5,然后自己构造文件名。这样,您就不必对用户输入和文件名进行各种疯狂的检查-您只需确保MD5是40个字符的字符串,其字符串是 [0-9a-f] ,那么您就很好。


I have a URL which will serve a protected file to my user.

The file name is re-written by my application when the file is uploaded, regardless of the name, and stored in my database. So I know it will never contain a "/" or ".."

The filename is: "USER_ID"_"RANDOMMD5".FILE_EXT With "USER_ID" = current logged in user ID and "RANDOM MD5" exactly that.

i.e. 5_ji3uc237uckj92d0jf3932t09ut93f2.pdf

This is my function to serve the file:

function user_file($file_name = "")
{
    if ($file_name)
    {
         // Ensure no funny business names:
         $file_name = str_replace ('..', '', $file_name);
         $file_name = str_replace ('/', '', $file_name);

         // Check if the user is allowed to access this file
     $user_id = substr($file_name, 0, strpos($file_name, "_"));

         // now do the logic to check user is logged in, and user is owner of file
         (($this->ion_auth->logged_in()) && (($user_id === $this->user->id))
         {
                // Serve file via readfile()
         }
    }
}

Question: Is this a secure way to ensure that there is no other way for the person to transverse directories, gain access to other files etc?

edit 1: ion_auth is my authentication library, and "$this->user->id" is the user id stored in my construct

edit 2: The user files are stored outside public_html - and thus only accessible via my application AFAIK

edit 3: My improved code, using the ideas from Amber below, taking into account the fact I need to accomodate for different file extensions, and I'm going to try and avoid a database hit:

function user_files($file_name = "")
{
    // for security reasons, check the filename is correct
    // This checks for a 32bit md5 value, followed by a single "." followed by a 3-4 extension (of only a-z)
    if (preg_match('^[A-Za-z0-9]{32}+[.]{1}[A-Za-z]{3,4}$^', $file_name))
    {
        // Now check the user is logged in
        if ($this->ion_auth->logged_in())
        {
            // Rewrite the request to the path on my server - and append the user_id onto the filename
            // This ensures that users can only ever access their own file which they uploaded
            // As their userid was appended to the filename during the upload!
            $file = MY_SECURE_FOLDER.$this->user->id.'_'.$file_name;

            // Now check if file exists
            if (file_exists($file))
            {
                // Serve the file
                header('Content-Type: '.get_mime_by_extension($file));
                readfile($file);
            }
        }
    }
}

解决方案

Better idea: have the user supply the MD5, and construct the filename yourself. That way you don't have to do all sorts of crazy checking for user input versus filenames - you can just ensure that the MD5 is a 40-character string of [0-9a-f] only, and then you're good.

这篇关于此PHP函数是否可以防止文件遍历?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆