限制文件访问——只能通过 PHP 读取

2021-12-19 00:00:00 pdf php iis restrict

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

I am using a GoDaddy web hosting plan on a Windows platform. This was not my choice -- it has to do with a different part of the actual site using ASP.NET (also not my choice).

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

I have a SQL database with a bunch of entries with some non-sensitive customer information. The primary key on this is an AutoIncrement integer, and I have a series of PDF files that match up with each of those integers (e.g. 555.pdf, 7891.pdf, etc).

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

My goal is to restrict direct access to these files, I want users to have to go through a search and login process (PHP) first. Originally I planned to put the files above the PUBLIC_HTML folder, but GoDaddy refuses to give me root access without a dedicated server ($20 a month from them).

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

The next thing I looked into was HTACCESS. I was going to restrict access to the files to only PHP scripts by only allowing access to the Server's IP Address (or localhost/127.0.0.1). Unfortunately this doesn't work because GoDaddy does not run Apache on its Windows servers.

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

I could put the files into BLOBs in the database, but that gets really messy when I need to work with them quickly (plus I have had some trouble with that approach).

是否有任何建议将文件的访问权限限制为 PHP 脚本(readfile())?

Any suggestions to restrict access to the files only to a PHP script (readfile())?

推荐答案

由于您不能将文件放在 public_html 目录之外的任何位置,因此您将不得不采用令人恐惧/讨厌的隐匿安全"方法

Since you can't put the files anywhere but in your public_html directory, you'll have to go for the feared/hated "security by obscurity" method

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

  1. Create a randomly named sub-directory to store the files in: public_html/RANDOMGARBAGE

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

Make sure the directory is not browseable. Disable directory browsing (if you can), and put a default document (index.html?) in there as well, so even if browsing is on, you won't get the directory listing.

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

Don't store your files with guessable names. Instead of storing them with the database ID, store them with a salted+hashed name instead: $crypted_filename = sha1($real_filename . 'some hard-to-guess salt text'); (of course, make this more complex if you need to). Store the original filename in your database. So you end up with something like:

public_html/RANDOMGARBAGE/5bf1fd927dfb8679496a2e6cf00cbe50c1c87145public_html/RANDOMGARBAGE/7ec1f0eb9119d48eb6a3176ca47380c6496304c8

通过 PHP 脚本提供文件 - 不要直接链接到散列文件名

Serve up the files via a PHP script - never link to the hashed filename directly

下载

然后这样做:

<?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 并开始下载秘密文件.pdf

This way the user will never see what your "s00per seekrit" filename is, they'll just see their browser hit ...php?fileID=37 and start a download of secret file.pdf

最重要的是,您可以偶尔定期将特殊子目录重命名为其他名称,以及更改盐文本(然后需要您使用新的 sha1 值更新所有散列文件名).

On top of this, you can occasionally rename the special sub-directory to something else on a regular basis, as well as change the salt text (which then requires you update all the hashed filenames with the new sha1 values).

相关文章