如何使用PHP在我的安全站点上显示受保护的Amazon S3映像?

时间:2011-03-02 19:54:32

标签: php image amazon-s3 amazon-web-services intranet

我正在尝试将我的网站图像从我的主机移动到Amazon S3云托管。这些图像属于客户工作站点,无法公开。我希望它们能够在我的网站上显示,最好是使用亚马逊提供的PHP SDK。

到目前为止,我已经能够为转换编写脚本,以便在数据库中查找记录,获取文件路径,对其进行适当命名,然后将其发送到亚马逊。

    //upload to s3
$s3->create_object($bucket, $folder.$file_name_new, array(
    'fileUpload' => $file_temp,
    'acl' => AmazonS3::ACL_PRIVATE, //access denied, grantee only own
    //'acl' => AmazonS3::ACL_PUBLIC, //image displayed
    //'acl' => AmazonS3::ACL_OPEN, //image displayed, grantee everyone has open permission
    //'acl' => AmazonS3::ACL_AUTH_READ, //image not displayed, grantee auth users has open permissions
    //'acl' => AmazonS3::ACL_OWNER_READ, //image not displayed, grantee only ryan
    //'acl' => AmazonS3::ACL_OWNER_FULL_CONTROL, //image not displayed, grantee only ryan
    'storage' => AmazonS3::STORAGE_REDUCED
    )
    );

在我复制所有内容之前,我创建了一个简单的表单来测试上传和显示图像。如果我使用ACL_PRIVATE上传图像,我可以获取公共网址,但我无权访问,或者我可以使用临时密钥获取公共网址并显示图像。

<?php
//display the image link
$temp_link = $s3->get_object_url($bucket, $folder.$file_name_new, '1 minute');
?>
<a href='<?php echo $temp_link; ?>'><?php echo $temp_link; ?></a><br />
<img src='<?php echo $temp_link; ?>' alt='finding image' /><br />

使用此方法,我的缓存将如何工作?我猜每次刷新页面或修改我的一条记录时,我都会再次拉动该图像,增加我的获取请求。

我还考虑过使用存储桶策略只允许从某些引用来检索图像。我是否正确理解亚马逊应该仅从我指定的页面或域中获取请求?

我引用了: https://forums.aws.amazon.com/thread.jspa?messageID=188183&#188183设置它,但后来我对我的对象需要哪种安全性感到困惑。看起来如果我将它们设为私有它们仍然不会显示,除非我使用前面提到的临时链接。如果我将它们公之于众,我可以直接导航到它们,无论引用者是谁。

我离开了我想要做的事吗?这不是S3真的支持,还是我错过了一些简单的东西?我已经完成了SDK文档和大量搜索,并且觉得这应该更清楚地记录下来,所以希望这里的任何输入都能在这种情况下帮助其他人。我读过其他人用文件命名这个文件的唯一ID,通过默默无闻来创造安全性,但这不会在我的情况下削减它,对于任何想要保证安全的人来说,这可能不是最好的做法。

4 个答案:

答案 0 :(得分:24)

提供图片的最佳方式是使用PHP SDK生成网址。这样下载就会直接从S3发送到您的用户。

您无需通过@mfonda建议的服务器下载 - 您可以在S3对象上设置您喜欢的任何缓存标头 - 如果您这样做,您将失去使用S3的一些主要好处。

但是,正如您在问题中指出的那样,url将始终在更改(实际上是查询字符串),因此浏览器不会缓存该文件。简单的解决方法就是始终使用相同的到期日期,以便始终生成相同的查询字符串。或者更好的是自己“缓存”网址(例如在数据库中)并且每次都重复使用它。

您显然必须在未来的某个地方设置到期时间,但如果您愿意,可以经常重新生成这些网址。例如,在您的数据库中,您将存储生成的URL和到期日期(您也可以从URL解析)。然后,您只需使用现有的URL,或者如果过期日期已过,则生成一个新的URL。等...

答案 1 :(得分:8)

您可以在Amazon存储桶中使用存储桶策略,以允许应用程序的域访问该文件。实际上,您甚至可以将本地开发域(例如:mylocaldomain.local)添加到访问列表中,您将能够获取图像。亚马逊在此处提供了示例存储桶策略:http://docs.aws.amazon.com/AmazonS3/latest/dev/AccessPolicyLanguage_UseCases_s3_a.html。这对帮助我提供图像非常有帮助。

下面的政策解决了让我参与这个SO主题的问题:

    {
       "Version":"2008-10-17",
       "Id":"http referer policy example",
       "Statement":[
    {
      "Sid":"Allow get requests originated from www.example.com and example.com",
      "Effect":"Allow",
      "Principal":"*",
      "Action":"s3:GetObject",
      "Resource":"arn:aws:s3:::examplebucket/*",
      "Condition":{
        "StringLike":{
          "aws:Referer":[
            "http://www.example.com/*",
            "http://example.com/*"
          ]
        }
      }
    }
  ]
}

答案 2 :(得分:2)

当您谈论安全性并保护数据免受未经授权的用户攻击时,有些事情是明确的:您必须在每次访问您有权访问的资源时进行检查。

这意味着,生成一个可以被任何人访问的URL(可能很难获得,但仍然......)。唯一的解决方案是图像代理。你可以用PHP脚本来做到这一点。

来自亚马逊博客的一篇精彩文章使用readfile http://blogs.aws.amazon.com/php/post/Tx2C4WJBMSMW68A/Streaming-Amazon-S3-Objects-From-a-Web-Server

进行提取
readfile('s3://my-bucket/my-images/php.gif');

答案 3 :(得分:0)

您可以从S3下载内容(在PHP脚本中),然后使用正确的标题提供它们。

作为一个粗略的例子,假设您在image.php中有以下内容:

$s3 = new AmazonS3();
$response = $s3->get_object($bucket, $image_name);
if (!$response->isOK()) {
    throw new Exception('Error downloading file from S3');
}
header("Content-Type: image/jpeg");
header("Content-Length: " . strlen($response->body));
die($response->body);

然后在您的HTML代码中,您可以

<img src="image.php">