我有一个名为 gallery.php 的 php 文件,它是用户特定图片库的页面。为了安全起见,用户图像存储在网络根目录之外。
为了为每个用户检索适当的文件,我使用了一个 getimage.php 文件,该文件从他们的位置提供图像。总而言之,目录结构如下所示:
- 用户图片
- 用户 1
- user1 的图片列表
- 用户 2
- user2 的图片列表
- 用户 1
- public_html
- 画廊.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'] 来确定要检索哪个图像,这可能是一个安全漏洞(也是一个主要漏洞)。我可以预见到目录遍历攻击,因此使用了真实路径,尽管我确信可能存在我未包含在该脚本中的其他攻击途径。
出于这个原因,我更愿意将 getimage.php 移动到 webroot 之外,或者至少防止它被直接访问(并且只能通过 gallery.php,其中发送的 img 参数完全在我的控制之下) .
然而,每当我尝试将 getimage.php 移出 public_html 时,即使我在 gallery.php 中要求或包含,我似乎也无法再调用它。我访问 getimage.php 的方式是这样做的:
<img src=getimage.php?img=IMG_FILENAME.jpg />
但是如果我将它移出 public_html 目录,getimage.php 将会失败。
那么,长话短说:我需要做什么来防止 getimage.php 被滥用?
最佳答案
最安全的方法是不使用 $_GET['img'] 传递图片 url,而是发送对图片的引用。
问题
首先,$_GET['img'] 可以是有害代码的任何外部 URL,使用 file_get_contents 可以直接下载它。
其次,任何人都可以使用您的服务器作为免费图像代理,只需在他自己的网站上使用以下 url:
<img src="http://www.yourwebsite.com/getimage.php?img=[external_image_url]">
正确的方法
1) 在您的数据库中创建包含用户图像路径的图像表。当您想要提供图像时,传递图像 ID 而不是 url:
$imageID = $_GET['image'];
.... your sql query here to retrieve the image....
$img = file_get_contents($imgString);
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 虚拟主机配置中,您可以使用:
Alias /getimage.php /path/to/getimage.php
5) 使用 404 not found 而不是 403 forbidden,不要给攻击者你捕获他的 Action 的暗示。
关于PHP - 访问 Web 根目录之外的文件的安全性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27613379/