如何防止非成员使用PHP直接访问私有内容

时间:2013-04-14 22:04:57

标签: php apache security password-protection

我知道.htaccess Apache方法可以保护非成员文件夹,但我想知道如何只用PHP来完成。

检查会话变量可以保护php页面,但有时可能会忽略对照片和/或pdf的直接访问。例如,如果我将一个直接链接复制到Facebook上的照片,注销,然后将我的浏览器指向照片的网址就显示没有问题。

Rapidshare等网站如何防止直接访问其内容?

我知道有一种方法可以在Apache中设置变量。也许有办法用Apache检查会话变量?

2 个答案:

答案 0 :(得分:5)

从问题和评论中,您似乎是在看起来像直接访问的URL之后,但是通过PHP脚本以允许授权下载它们。我不知道你当前的目录结构,所以我打算为这个答案的测试用例做一个 - 虽然是一个小的列表:

public-html/
    content/        <- where the actual files are
        .htaccess   <- to deny access to the directory
    .htaccess       <- the one created here
    download.php    <- download script

由此,我们假设所有文件都位于/content,而“直接链接”看起来就像是/file

/content/.htaccess

deny from all

下一个注意到第一个RewriteRule,以便不会覆盖已存在的普通文件,并且以前的.htaccess会阻止访问该目录中的文件。如果您使用的是.htaccess,则重要规则是最后一个规则,如果匹配则会停止处理,因此请将其放在现有.htaccess中。

/.htaccess

<IfModule mod_rewrite.c>
    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} -s [OR]
    RewriteCond %{REQUEST_FILENAME} -l [OR]
    RewriteCond %{REQUEST_FILENAME} -d
    RewriteRule ^.*$ - [NC,L]

    RewriteRule ^file/(.+)$ download.php?file=$1 [L]
</IfModule>

有了这个,如果转到/file/myDocument.pdf,它就像是对文件的直接访问,并且会像download.php?file=myDocument.pdf一样发送到脚本。

从那里,创建要使用的下载脚本是一个问题。我发布的是Armand Niculescu found here的修改版本。我只在这里发布相关部分(the entirety can be found on PasteBin,您可以在其中修改此处发布的部分以满足您的需求):

/******************************
 * PERFORM AUTHORIZATION HERE *
 *   The following is added   *
 ******************************/
if($_SESSION['validated'] !== true) {
    //Not authorized to download, send header and exit
    header("HTTP/1.0 401 Unauthorized");
    exit;
}

我还对8行正确的文件路径进行了另一次小编辑:

$file_path  = './content/' . $file_name;

这就是如何获得一个有效的下载脚本并使其看起来像直接文件访问的小例子。

答案 1 :(得分:2)

从您的问题我得知您已经知道如何保护文件夹免受直接访问以及如何保护PHP脚本。所以你需要的是一个受保护的php脚本,提供对文件的间接访问(正如评论中已经提到的那样)。

创建此下载脚本时,您应该记住一些重要的细节:

  • 提供mime类型。在许多情况下,header("Content-Type: application/octet-stream")就足够了,但
  • 告诉客户下载文件(而不是显示文件)并提供文件名:header('Content-Disposition: attachment; filename="' . basename($path) . '"')
  • 提供文件大小:header("Content-Length: " . filesize($path));
  • 为了避免大文件出现问题,您应该使用以下内容而不是readfile

    $file = fopen($path, 'r');
    flush(); 
      while (!feof($file)) { 
      print(fread($file, 4096)); 
      flush(); 
    }
    fclose($file);