PHP-访问web根目录以外文件的安全性

PHP-访问web根目录以外文件的安全性,php,html,image,.htaccess,security,Php,Html,Image,.htaccess,Security,我有一个名为gallery.php的php文件,它是用户特定图像库的页面。为了安全起见,用户映像存储在web根目录之外 为了为每个用户检索适当的文件,我使用一个getimage.php文件,该文件从图像的位置为图像提供服务。总之,目录结构如下所示: 用户图像 用户1 user1的图像列表 用户2 user2的图像列表 公共网页 gallery.php getimage.php getimage.php编写如下: $imgString = realpath('/UserImag

我有一个名为gallery.php的php文件,它是用户特定图像库的页面。为了安全起见,用户映像存储在web根目录之外

为了为每个用户检索适当的文件,我使用一个getimage.php文件,该文件从图像的位置为图像提供服务。总之,目录结构如下所示:

  • 用户图像
    • 用户1
      • user1的图像列表
    • 用户2
      • user2的图像列表
  • 公共网页
    • gallery.php
    • getimage.php
getimage.php编写如下:

$imgString = realpath('/UserImages/' . $_SESSION['username'] . '/' . $_GET['img']);
if (!startsWith($imgString, '/UserImages/' . $_SESSION['username'] . '/')
    || !(endsWith(strtolower($imgString), '.jpg') || endsWith(strtolower($imgString), '.jpeg')))
{
    header('HTTP/1.0 403 Forbidden');
    die();
}

$img = file_get_contents($imgString);
header("Content-type: image/jpeg");
echo($img);
exit();
我依靠$_GET['img']来确定要检索的图像,这可能是一个安全漏洞(而且是一个主要漏洞)。我可以预见目录遍历攻击,因此使用realpath,尽管我确信这个脚本中可能不包含其他攻击途径

出于这个原因,我希望我能将getimage.php移到webroot之外,或者至少阻止它被直接访问(并且只能通过gallery.php,在gallery.php中,发送的img参数严格由我控制)

然而,每当我试图将getimage.php移出public_html的时候,我似乎再也不能调用它了,即使我在gallery.php中做了一个require或include。我访问getimage.php的方式是:

<img src=getimage.php?img=IMG_FILENAME.jpg />

但是如果我将getimage.php移出public_html目录,它将失败

所以,长话短说:我需要做什么来防止getimage.php被滥用?

您需要允许Apache(假定)使用目录指令()访问带有图像的文件夹


或者,您可以将图像移动到根目录下,并使用.htaccess限制对它们的直接访问,如果您想保护它们。

使用目录结构执行此操作的唯一方法是清除$\u GET['img']变量,并确保它没有任何不需要的字符

您可以使用正则表达式来实现这一点,该正则表达式过滤除字母、数字、下划线、连字符和点之外的所有内容

尝试用以下内容替换代码的第一行

$imgString = realpath('/UserImages/' . $_SESSION['username'] . '/' . preg_replace("/[^a-zA-Z0-9._-]/", "", $_GET['img']));
或者,您可以在代码之前使用这个简单的if语句检查$\u GET['img']变量是否包含错误字符

if(preg_replace("/[^a-zA-Z0-9._-]/", "", $_GET['img']) != $_GET['img']){
    // Throw an error
    exit();
}

PS:在读取文件之前别忘了检查文件是否存在,否则会出错。您可以使用文件的存在作为额外的安全检查。

最好的安全方法是不要使用$\u GET['img']传递图像url,而是发送对图像的引用

问题

首先,$\u GET['img']可以是有害代码的任何外部url,通过文件内容,您可以直接下载它

其次,任何人只要在自己的网站上使用以下url即可将您的服务器用作免费图像代理:

<img src="http://www.yourwebsite.com/getimage.php?img=[external_image_url]">
2) 因为您知道$_GET['image']是一个ID,所以可以轻松地对其进行清理:

if( !preg_match("/^[0-9]+$/", $_GET['image']) )
{
    header('HTTP/1.1 404 Not Found');
    exit();    
}
3) 在SQL中,不要忘记使用准备好的语句:

$sql = "SELECT image_path from images WHERE id = ?";
4) 只有图像应该移到文档根文件夹之外,如果您想将getimage.php移到根文件夹之外,您可以使用Apache Alias提供服务。在Apache Virtualhost配置中,您可以使用:

Alias /getimage.php /path/to/getimage.php

5) 使用404 not found而不是403 forbidden,不要暗示攻击者你抓到了他的行动。

由于图像将在web上提供,我认为将它们存储在web根目录之外不是一个好主意,因为为了提供它们,无论如何都需要创建一个安全漏洞。相反,我会验证上传的文件是否真的是图像,然后让它们可以访问web。我不需要上传检查,因为所提供的文件都是我自己制作的。用户只需要能够看到它们。如果我将用户图像放在web根目录中,如何防止除User1之外的任何人访问User1的文件?我不明白为什么需要保护某些图像。在我看来,你的剧本似乎是这里的问题。为什么不将您的图像移动到子域(完全独立于您的应用程序)并从那里为其提供服务?我如何通过知道他人图像文件的URL来防止未经授权的用户访问他们不应该访问的图像?我想使用这样的解决方案,结合登录页面,但我不知道如何使用。有没有一种方法可以将.htaccess与登录页面结合使用,而不是使用基于浏览器的弹出框?当然可以。您可以使用rewrite()将所有请求(css、ico和js除外)转发到您的页面,在该页面上,您可以使用登录名和脚本在.htaccess中提供类似“RewriteRule!\(js | ico | css)$index.php”的图像
Alias /getimage.php /path/to/getimage.php