我正在尝试使用 NGiNX 和 PHP 保护我的服务器上的文件(多种类型)。
基本上,我希望人们在访问静态文件(如图片)时必须登录网站。DropBox 在这方面做得很好。而他们却强迫你登录才能访问你放在服务器上的任何静态文件。
我考虑使用 NGiNX Perl 模块。我会编写一个 perl 脚本来检查会话,看看用户是否已登录,以便让他们访问静态文件。
我更喜欢使用 PHP,因为我的所有代码都在 PHP 下运行,而且我不确定如何使用 PERL 检查由 PHP 创建的会话。
所以基本上我的问题是:如何保护需要用户登录并使用 PHP 脚本创建有效会话的任何类型的静态文件?
答案1
你问的是两件事:
- 如何防止外部访问文件(或文件集)
- 如何验证用户身份并允许 PHP(和用户)访问文件
希望这可以阐明每个组件所起的作用 - 尽管可能有点过分。
防止外部访问文件:
这部分由您的 Web 服务器完成 - 在本例中为 nginx。
在您的 nginx 配置(您的服务器块)中,您可以指定一个root
路径。默认情况下,此根路径下的所有文件都可以直接访问。
例如,考虑以下内容(域名为“example.com”)
root /var/www/example.com/public_html
如果您有一个文件,uploaded_file.zip
则可以通过以下方式访问:
- 位置:/var/www/example.com/public_html/uploaded_file.zip -无障碍通过 example.com/uploaded_file.zip
- 位置:/var/www/example.com/uploaded_file.zip -无法访问(即使使用 example.com/../uploaded_file.zip)
本质上,文档根目录上方的文件无法通过浏览器访问,但是,大多数 PHP 配置将允许您的代码读取文件并传送它(对此的限制通常是由于open_basedir
)
在某些情况下,最好将文件放在文档根目录下。要做到这一点并防止(直接)外部访问,您将使用指令internal
。例如:
位置 /uploads { 内部; }
现在,放置在 /var/www/example.com/public_html/uploads 中的任何文件都只能在内部访问(即无法通过浏览器访问,但可以通过 PHP 脚本访问)。如果需要,您还可以在 /uploads 位置上设置别名,以便也可以使用其他路径来引用它。
此时,您的文件不能直接访问,但您的脚本仍然可以为其提供服务。
用户身份验证和 PHP:
考虑以下基本设计:用户可以直接访问文件,也可以进入登录页面。如果他们尝试直接访问文件并且已登录(并具有权限),则将下载该文件,否则,他们将最终进入登录屏幕。要上传文件,用户需要登录。
假设您的下载脚本(将文件传递给用户的页面)名为“download.php”。典型的 URL 可能是 example.com/download.php?file=uploaded_file.zip。您很可能不希望 URL 包含 php 文件名。为了避免这种情况,您可以在 nginx 配置中设置重写规则,将另一个位置(假设为 /files)指向您的脚本。将以下内容添加到您的 nginx 配置中:
rewrite ^/files/(.*) /download.php?file=$1 last;
(这相当于改变以 /files 开头的任何请求的请求路径,并捕获 / 之后的所有内容并将其作为查询参数传递给您的 php 文件);
现在,您可以通过以下方式访问您的文件:example.com/files/uploaded_file.zip(内部重定向到您的 php 脚本)。
您的 PHP 文件 (download.php) 现在执行以下操作:
- 开始会话
- 如果用户已登录,则继续,否则,重定向到登录页面,并将目标文件作为查询字符串的一部分传递
- 查询你的数据库(例如 MySQL)以查看用户是否可以访问此文件
- 如果用户有权限,则继续,否则,重定向到错误页面
输出必要的标题(Content-Type,Content-Disposition等)并设置:
X-Accel-Redirect: /uploads/uploaded_file.zip;
请注意,您可以完全通过 PHP 进行实际下载(例如使用readfile
)——它只是效率更高一点,尤其是对于大文件而言)而不是通过 nginx 进行下载。此外,尽管用户似乎直接访问文件,但在内部,它要经过 PHP 的验证,PHP 会在允许他们继续之前对其进行身份验证。
URL -> nginx (redirect to PHP) -> PHP (authenticate) -> nginx (serve file)
在上传方面,您将move_uploaded_file
访问 /var/www/example.com/public_html/uploads(受“internal”指令保护,因此文件不能直接访问),并将权限保存到您的数据库。