【问题标题】:Securing a PHP file manager from its users保护 PHP 文件管理器免受其用户的侵害
【发布时间】:2010-10-11 02:56:19
【问题描述】:

大家好,我正在开发一个使用CodeIgniter PHP framework 的照片共享网站。这个想法是人们可以上传他们的照片,管理它们(通过某种文件浏览器,允许他们创建子文件夹,拖动文件等)和编辑它们(一些基本的东西,比如调整大小,旋转和裁剪开始,和稍后,我将添加一些高级功能。

我已经为 CI (Redux Authentication 2 Beta) 实现了第三方身份验证解决方案,我现在正在集成一个 JS/PHP 文件管理器 (AjaxExplorer),但问题是用于管理文件的 PHP 后端 (移动、复制等)过于信任来自 ajax 调用的用户输入。例如,它正在做这样的事情(为了清楚起见进行了简化):

move_uploaded_file($_FILES['upload']['tmp_name'], $root.$username.$_POST['destination_dir']);

如您所见,存在明显的安全问题,因为它盲目地接受用户输入的任何路径!我已经可以看到有人将“../AnotherUser/”之类的内容作为 $_POST['destination_dir'] 值发送。

我的问题是:“沙箱”用户的最佳方式是什么,以便只允许他管理自己的数据?我是否只是验证+过滤输入,希望捕捉到每一个入侵企图?是否有专门用于解决此特定问题的库/包?

我认为这个问题必须在任何(足够成熟的)项目中以某种方式解决,它赋予用户通过网络浏览器管理文件的能力,所以我希望找到一些明确的指导方针(因为有很多关于 SQL 注入、XSS、CSRF 等),但我想我没有使用正确的关键字。

【问题讨论】:

    标签: php ajax security file codeigniter


    【解决方案1】:

    “沙箱”用户的最佳方式是什么,以便只允许他管理自己的数据?

    允许用户想要的任何文件名/目录名,但不要在服务器端文件系统上使用它们。相反,将路径名写入带有主键的数据库,并将主键用作平面存储目录中的文件名,如“34256.dat”(如果您愿意,甚至可以作为数据库中的 BLOB)。然后通过下载脚本或 URL 重写提供服务,使所需的文件名出现在 URL 中。

    清理传入的文件名很难。检测“..”只是开始。文件名过长;文件名太短;前导点和尾随点的组合;前导和尾随空格的组合;不同平台的不同目录分隔符;在某些平台上无效的字符;控制字符; Unicode 字符和特定环境的寻址方式; ADS;对您的网络服务器来说可能是“特殊”的文件名(“.htaccess”)或扩展名(“.php”、“.cgi”); Windows 的保留文件名...

    您可以花费一生的时间来追踪各种平台上有趣的文件路径规则的小怪癖,或者您可以忘记它并使用数据库。

    【讨论】:

    • 感谢 bobince 的回答!这是一个很好的解决方案,但我担心数据的可移植性,因为对文件进行简单备份意味着首先运行一些脚本来反转命名方案,如果我的数据库受到损害或损坏,我会失去目录的树结构。
    • 很好的解决方案。 @fandelost,然后确保备份数据库和文件
    • 很抱歉这么久才回复。我终于辞去了“AjaxExplorer”的职务,并根据 bobince 的建议构建了自己的文件管理解决方案,使用数据库来存储与文件相关的所有内容,但在将它们上传到 Web 根目录之外后就不再碰它们了。我还将每个人的“名称”字段限制为一组有限的字符,并且我不会使用嵌套文件夹,而是使用单级分组(只是为了避免参考混乱)。
    • hmm 我有疑问,因为您创建了数据库依赖项,但另一方面,查询数据库比文件系统更容易用于搜索/排序目的,而且更安全......
    【解决方案2】:

    据我所知,没有图书馆。
    但是在您的特定示例中,从字符串中删除所有(反)斜杠和点,然后在其末尾附加一个斜杠,这样用户就无法更改文件夹。

    $destdir = str_replace(array('.', '/', '\\'), '', $_POST['destination_dir']); 
    $destdir .= "/";
    

    【讨论】:

    • 包含所有无效字符的字符串被映射到服务器根文件夹。
    • 感谢您的回答,但是 AFAIK 点、斜杠和反斜杠都是可以用于命名文件夹的字符,至少在 *NIX 世界中是这样。
    • 不那么真实 bobince,因为我可以预先设置路径,但无论如何我都不会使用此解决方案。
    【解决方案3】:

    我不确定您的destination_dir 是什么样的,但我想到的是分配目录键,然后根据该键获取目录。例如:

    //$_POST['destination_dir'] = '4hg43h5g453j45b3';
    *_query('SELECT dir FROM destinations WHERE key = ? LIMIT 1'); //etc.
    

    但是,您必须事先预定义键。另一种选择可能相反:md5/sha1 输入并将其用作destination_dir,然后将该键与相关标签一起存储在数据库中。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多