【问题标题】:Restrict file access -- only read through PHP [closed]限制文件访问——仅通过 PHP 读取 [关闭]
【发布时间】:2010-08-12 23:20:59
【问题描述】:

我在 Windows 平台上使用 GoDaddy 网络托管计划。这不是我的选择——它与使用 ASP.NET 的实际站点的不同部分有关(也不是我的选择)。

我有一个 SQL 数据库,其中包含一些包含一些非敏感客户信息的条目。这方面的主键是一个 AutoIncrement 整数,我有一系列与每个整数匹配的 PDF 文件(例如 555.pdf、7891.pdf 等)。

我的目标是限制对这些文件的直接访问,我希望用户必须先通过搜索和登录过程 (PHP)。最初我计划将文件放在 PUBLIC_HTML 文件夹上方,但 GoDaddy 拒绝在没有专用服务器的情况下给我 root 访问权限(他们每月 20 美元)。

接下来我研究的是 HTACCESS。我打算通过只允许访问服务器的 IP 地址(或 localhost/127.0.0.1)来限制对文件的访问仅限于 PHP 脚本。不幸的是,这不起作用,因为 GoDaddy 不在其 Windows 服务器上运行 Apache。

我可以将文件放入数据库中的 BLOB 中,但是当我需要快速处理它们时会变得非常混乱(而且我在使用这种方法时遇到了一些问题)。

有什么建议可以限制对文件的访问仅限于 PHP 脚本 (readfile())?

【问题讨论】:

  • 这取决于他们使用的 Web 服务器(假设是 IIS)。也许你应该用 IIS 标记它。

标签: php pdf iis restrict


【解决方案1】:

由于您不能将文件放在 public_html 目录以外的任何地方,您将不得不采用令人恐惧/讨厌的“默默无闻的安全性”方法

  1. 创建一个随机命名的子目录来存储文件在:public_html/RANDOMGARBAGE

  2. 确保目录不可浏览。禁用目录浏览(如果可以的话),并在其中放置一个默认文档(index.html?),这样即使打开浏览,您也不会得到目录列表。

  3. 不要以可猜测的名称存储文件。不要将它们与数据库 ID 一起存储,而是使用加盐+散列的名称来存储它们:$crypted_filename = sha1($real_filename . 'some hard-to-guess salt text');(当然,如果需要,可以使其更复杂)。将原始文件名存储在数据库中。所以你最终会得到类似的东西:

    public_html/RANDOMGARBAGE/5bf1fd927dfb8679496a2e6cf00cbe50c1c87145 public_html/RANDOMGARBAGE/7ec1f0eb9119d48eb6a3176ca47380c6496304c8

  4. 通过 PHP 脚本提供文件 - 切勿直接链接到散列文件名

    下载

然后这样做:

<?php

    $fileID = (int)$_GET['fileID'];

    $crypted_file = sha1($fileID . 'some hard-to-guess salt text');

    $full_path = 'public_html/RANDOMGARBAGE/' . $crypted_file;
    if (is_readable($full_path)) {
         if(user_is_allowed_to_see_this_file()) {
             /// send file to user with readfile()
             header("Content-disposition: attachment; filename=$ORIGINAL_FILENAME");
             readfile($full_path);
         } else {
             die("Permission denied");
         }
    } else {
        /// handle problems here
        die("Uh-oh. Can't find/read file");
    }

这样用户将永远不会看到你的“s00per seekrit”文件名是什么,他们只会看到他们的浏览器点击...php?fileID=37并开始下载secret file.pdf

除此之外,您偶尔可以定期将特殊子目录重命名为其他名称,以及更改 salt 文本(这需要您使用新的 sha1 值更新所有散列文件名)。

【讨论】:

    【解决方案2】:

    您可以简单地隐藏它们。这是通过默默无闻的安全性,但如果您不能将它们排除在网络根目录之外,或者找到一种方法告诉服务器不要直接为它们提供服务,这听起来是您的最佳选择。

    所以把它们放在一些随机命名的目录中:

    asd8b8asd8327bh/123.pdf
    asd8b8asd8327bh/124.pdf
    asd8b8asd8327bh/125.pdf
    ...
    

    然后自己编写一个小的 PHP 脚本,它将发送适当的标头,并传递文件内容。

    例如:

    <?PHP
    //pdf.php
    $id = $_GET['id'];
    
    //make sure nobody is doing anything sneaky. is_numeric() might do the trick if the IDs are always integers.
    if (!some_validation_passes($id)){
      die();
    }
    <?php
    
    header('Content-type: application/pdf');
    header('Content-Disposition: attachment; filename="'.$id.'.pdf"');
    readfile('asd8b8asd8327bh'.$id.'pdf');
    

    现在,以上内容实际上并没有比直接提供文件更好(还),因为人们仍然可以在查询字符串中增加 id 参数。

    但是你应该能够很容易地弄清楚如何处理授权。

    【讨论】:

    • 这是通过默默无闻的安全。换句话说,不安全。
    • @Borealid 你这么说好像我没有在第一行明确限定我的答案。不要通过默默无闻来讨论安全性,而是“这是软件。换句话说,不安全”。或“这是一个密码系统,因此不安全”。事实上,现在我想一想,我的解决方案与强密码一样安全,假设没有不相关的漏洞让攻击者列出目录。
    【解决方案3】:

    因为 PHP 使用 web 服务器用户的权限,所以没有办法限制对文件的访问:

    • 将它们放在 DOCROOT 之外
    • 更改 Web 服务器配置以禁止访问这些文件
    • 更改文件以使其被 Web 服务器解释,从而隐藏其内容

    将它们放入数据库算作 DOCROOT 之外。对于第三个选项,您可以将 PDF 制作成 PHP 文件,但老实说,这会非常复杂。

    我建议你联系 GoDaddy,看看他们是否有办法配置每个目录的文件权限。

    【讨论】:

    • 聪明。假设 OP 不能对服务器做任何事情,我喜欢你的第三个选项,再加上我概述的基本代码。
    【解决方案4】:

    通过 chmod 使文件夹 web 不可访问。 PHP 仍然可以包含/要求服务器上的任何内容,但用户将永远无法导航到文件。

    示例: 这个设置为770,IE用户和组可以读/写/执行,其他什么都做不了。

    【讨论】:

    • 这个答案是错误的。除非 SuExec/CGI 配置,PHP 使用 Web 服务器的权限。如果 Web 服务器无法访问该文件,那么 PHP 也无法访问该文件。
    • 我有一个文件夹设置为 770,我可以包含,但无法直接在浏览器中导航。
    • 另外我想你误会了,web服务器还是有权限的,用户和组在770有权限,其他人没有。因此,这使 PHP 可以完全访问文件,Web 浏览器将一无所获。
    • 我不明白如果不是linux系统我怎么能chmod进入系统!?
    • 如果您不在 linux 系统上,请查找 Windows 环境的等效安全设置。
    猜你喜欢
    • 1970-01-01
    • 2020-01-02
    • 2020-01-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-01-01
    • 1970-01-01
    相关资源
    最近更新 更多