提问人:Pekka 提问时间:11/7/2009 最后编辑:GEOCHETPekka 更新时间:11/30/2017 访问量:2481
以性能为导向的方法来保护PHP级别的文件?
Performance-oriented way to protect files on PHP level?
问:
我正在寻找一些关于我一直在思考的事情的意见。这是一个非常普遍的问题,也许有我还没有想到的解决方案。
我有一个基于PHP的CMS。
对于在CMS中创建的每个页面,用户可以上传资产(要下载的文件,图像等)
这些资源存储在一个目录中,我们称之为“/myproject/assets”,每页(1 个子目录 = 1 个页面,例如“/myproject/assets/page19283”)
用户可以在 CMS 中“取消发布”(隐藏)页面。当一个页面被隐藏时,有人试图访问它,因为他们记住了 URL 或者他们来自 Google 或其他东西,他们会收到一条“未找到”消息。
但是,这些资产仍然可用。我也想保护它们,这样当用户取消发布页面时,他们可以相信它已经完全消失了。(对于司法问题非常重要,例如法院命令删除内容......这样的事情可能会发生)。
最明显的方法是将所有资产存储在一个安全的目录中(= Web 服务器无法访问),并使用 PHP“前门”在检查后将文件传递出去。当一个项目需要无懈可击时,这是我目前的做法,但我不喜欢它,因为 PHP 解释器会为网站上的每个微小图像、脚本和样式表运行。我想要一个更快的方法。
.htaccess保护(拒绝所有或类似)并不完美,因为CMS应该是可移植的,并且能够在共享环境中运行。我希望它甚至可以在 IIS 和其他 Web 服务器上运行。
我现在能想到的最好的方法是在未发布时将特定页面的资产目录移动到安全位置,并在发布时将其移回。但是,管理员用户需要能够看到该页面,即使该页面未发布,因此我必须解决必须从安全目录提供这些资产的事实。
谁能想出一种方法,允许Apache直接访问文件(=不通过PHP脚本),但仍然使用PHP控制访问?我不能。
我还会考虑一个简单的 .htaccess 解决方案,它可能会在大多数共享环境中运行。
答:
编辑:管理界面的混合怎么样?在 ACP 中,您可以通过 PHP 方法访问,基本上,将所有文件请求发送到 PHP 身份验证文件,但对于公共文件,您可以使用 HTTP AUTH/htaccess 来确定结果的可用性。这为您提供了公共端的性能,但提供了 ACP 端的保护。
旧消息:
使用mod_rewrite类型操作时,.htaccess 与大多数 Apache 和 IIS<7 环境(使用各种 ISAPI 模块)兼容。唯一的例外是 IIS7 + 使用 web.config 文件的新重写模块。但是,我愿意您可以有效地为此实例生成/更改 web.config 文件,而不是使用 .htaccess。
鉴于此,您可以使用 rewrite 方法设置重定向并重定向到您的自定义 404 页面(希望发送正确的 404 标头)。这不是 100% 合适的,因为实际资产应该是提供 403 标头的资产,但是......它有效。
除非您想为每个服务器平台正确创建HTTP AUTH设置,否则我会走这条路线。另外,如果你做对了,你可以使你的系统可扩展,以允许你或你的用户将来使用其他类型(包括一个基于php的选项,如果他们想这样做的话)。
评论
任何敏感的东西都应该像你建议的那样存放在安全的区域。
如果您的网站位于 /var/www/public_html
将资产放在 /var/www/assets 中的 Web 可访问区域之外 PHP可以调用下载,或者您可以根据需要通过PHP提供文件。
如果您将 HTML 保留在 CMS 数据库中,则只会留下非敏感图像和 CSS。
如果您绝对必须打开和关闭对所有材料的所有访问,我认为您最好的选择可能是符号链接。将 -everything- 保留在无法访问 Web 的区域中,并将每个资产文件夹符号链接到 Web 区域。这样,如果您需要完全锁定人员,只需删除符号链接而不是删除所有文件即可。
我不喜欢它,但这是我能想到的唯一适合你的东西。
评论
我会去实现一个网关。您将 .htaccess 文件设置为指向网关 .php 脚本的 /assets/ URL,如果两个凭据都无效并且此特定文件未发布或显示它,则该脚本将拒绝。
我有点困惑。您是否还需要保护样式表文件和图像?也许移动此文件夹是最好的选择。
我假设“页面”是由PHP生成的,而“资产”不应该需要PHP。(如果我弄错了,请告诉我。
您可以重命名 assets 文件夹。例如,将“/myproject/assets/page19283”重命名为“/myproject/assets/page19283-hidden”。这将破坏所有旧的、记忆的链接。当您为可以看到该页面的管理员用户生成页面时,只需使用新文件夹名称编写 URL。毕竟,您知道该页面是否“隐藏”。如果您知道“秘密”网址,则可以直接访问资产。
为了提高安全性,请使用一堆随机文本重命名文件夹,并将其存储在页表中(存储隐藏标志的任何位置):“/myproject/assets/page19283-78dbf76B&76daz1920bfisd6g&dsag”。这将使猜测隐藏的 url 变得更加困难。
评论
只需将 GUID 预置或追加到数据库中的页面名称和文件系统中的资源目录中即可。管理员仍然可以从管理界面查看它,因为链接将更新,但 GUID 有效地使外部用户或搜索引擎无法发现该页面。
评论
我只是阻止任何非HTML文件的热链接,因此所有“资产”内容只能从HTML页面访问。删除(或保护)页面只是删除所有内容,而不必弄乱整个文件系统。
评论
将您的信息存储在 Web 根目录之外的目录中(即:public_html 或 htdocs 之外的一个目录)。然后,在 php 脚本中使用 readfile 运算符在请求时代理文件。readfile(...) 基本上采用单个参数(文件的路径)并打印该文件的内容。
这样,您可以创建一个屏障,如果访问者请求隐藏在代理后面的信息,即使他们“记住”了 URL,您也可以使用 404 或 403 拒绝他们。
评论
使用 X-Sendfile
最好和最有效的方法是使用 X-Sendfile。但是,在使用 X-Sendfile 之前,您需要在 Web 服务器上安装和配置它。
如何执行此操作的方法将取决于您使用的 Web 服务器,因此请查找特定服务器的说明。实施起来应该只有几个步骤。实施后,不要忘记重新启动 Web 服务器。
安装 X-Sendfile 后,您的 PHP 脚本只需检查登录用户,然后提供该文件。下面可以看到一个使用会话的非常简单的例子:
session_start();
if (empty($_SESSION['user_id'])){
exit;
}
$file = "/path/to/secret/file.zip";
$download_name = basename($file);
header("X-Sendfile: $file");
header("Content-type: application/octet-stream");
header('Content-Disposition: attachment; filename="' . $download_name . '"');
重要提示:
如果您想从另一个网页(例如图像 src 值)提供文件,则需要确保清理文件名。您不希望任何人覆盖您的脚本并使用“..”等来访问您系统上的任何文件。
因此,如果您有如下所示的代码:
<img src="myscript.php?file=myfile.jpg">
然后你会想做这样的事情:
session_start();
if (empty($_SESSION['user_id'])){
exit;
}
$file = preg_replace('/[^-a-zA-Z0-9_\.]/', '', $_GET['file']);
$download_name = basename($file);
header("X-Sendfile: $file");
header("Content-type: application/octet-stream");
header('Content-Disposition: attachment; filename="' . $download_name . '"');
评论