我有一个名为gallery.php的php文件,它是用户特定图像库的页面。为了安全起见,用户图像存储在Web根目录之外。
要为每个用户检索相应的文件,我使用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,虽然我确信可以有其他攻击途径,我不包含这个脚本。
出于这个原因,我更愿意,如果我可以在webroot之外移动getimage.php,或者至少阻止它直接访问(并且只能通过gallery.php,其中发送的img参数严格在我的控制之下)
每当我尝试移动public_html的getimage.php oustide时,即使我在gallery.php中执行require或include,我似乎也无法再调用它。我访问getimage.php的方式就是这样做:
<img src=getimage.php?img=IMG_FILENAME.jpg />
但如果我将它移出public_html目录,getimage.php将会失败。
所以,长话短说:我需要做些什么才能防止getimage.php被滥用?
答案 0 :(得分:2)
最安全的方法是不使用$ _GET ['img']传递图片网址,而是发送对图片的引用。
问题
首先,$ _GET ['img']可以是有害代码的任何外部网址,而使用file_get_contents则直接下载。
其次,任何人都可以通过在自己的网站上使用以下网址将您的服务器用作免费图片代理:
<img src="http://www.yourwebsite.com/getimage.php?img=[external_image_url]">
正确的方式
1)在数据库中创建包含用户图像路径的图像表。当您想要提供图像时,请传递图像ID而不是网址:
$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移到root之外,你也可以使用Apache Alias来提供它。在Apache Virtualhost配置中,您可以使用:
Alias /getimage.php /path/to/getimage.php
5)使用404 not found而不是403禁止,不要给攻击者一个提示你抓住了他的动作。
答案 1 :(得分:1)
您需要允许Apache(假设)使用Directory指令(http://httpd.apache.org/docs/2.2/mod/core.html#directory)访问包含图像的文件夹。
或者您可以在根目录下移动图像,并使用.htaccess限制对它们的直接访问,如果您想保护它们。
答案 2 :(得分:1)
使用目录结构执行此操作的唯一方法是清除$ _GET ['img']变量并确保它没有任何不需要的字符。
您可以使用正则表达式来执行此操作,该表达式可以过滤除字母,数字,下划线,连字符和点之外的所有内容。
尝试用此代码替换代码的第一行......
$imgString = realpath('/UserImages/' . $_SESSION['username'] . '/' . preg_replace("/[^a-zA-Z0-9._-]/", "", $_GET['img']));
或者,您可以检查$ _GET ['img']变量是否包含错误字符,并在代码之前使用这个简单的If语句。
if(preg_replace("/[^a-zA-Z0-9._-]/", "", $_GET['img']) != $_GET['img']){
// Throw an error
exit();
}
PS:在阅读之前不要忘记检查文件是否存在,否则会出现错误。您可以将文件存在作为附加安全检查。