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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5172630/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-25 20:30:20  来源:igfitidea点击:

How do I display protected Amazon S3 images on my secure site using PHP?

phpimageamazon-s3amazon-web-servicesintranet

提问by Bob

I am trying to move images for my site from my host to Amazon S3 cloud hosting. These images are of client work sites and cannot be publicly available. I would like them to be displayed on my site preferably by using the PHP SDK available from Amazon.

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

So far I have been able to script for the conversion so that I look up records in my database, grab the file path, name it appropriately, and send it to Amazon.

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

    //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
    )
    );

Before I copy everything over, I have created a simple form to do test upload and display of the image. If I upload an image using ACL_PRIVATE, I can either grab the public url and I will not have access, or I can grab the public url with a temporary key and can display the image.

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

<?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 />

Using this method, how will my caching work? I'm guessing every time I refresh the page, or modify one of my records, I will be pulling that image again, increasing my get requests.

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

I have also considered using bucket policies to only allow image retrieval from certain referrers. Do I understand correctly that Amazon is supposed to only fetch requests from pages or domains I specify?

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

I referenced: https://forums.aws.amazon.com/thread.jspa?messageID=188183&#188183to set that up, but then am confused as to which security I need on my objects. It seemed like if I made them Private they still would not display, unless I used the temp link like mentioned previously. If I made them public, I could navigate to them directly, regardless of referrer.

我参考了:https: //forums.aws.amazon.com/thread.jspa?messageID=188183来设置它,但随后对我的对象需要哪种安全性感到困惑。似乎如果我将它们设为私有,它们仍然不会显示,除非我使用前面提到的临时链接。如果我将它们公开,我可以直接导航到它们,而不管推荐人如何。

Am I way off what I'm trying to do here? Is this not really supported by S3, or am I missing something simple? I have gone through the SDK documentation and lots of searching and feel like this should be a little more clearly documented so hopefully any input here can help others in this situation. I've read others who name the file with a unique ID, creating security through obscurity, but that won't cut it in my situation, and probably not best practice for anyone trying to be secure.

我离我在这里要做的事情很远吗?这不是 S3 真正支持的,还是我错过了一些简单的东西?我已经浏览了 SDK 文档并进行了大量搜索,我觉得这应该更清楚地记录下来,所以希望这里的任何输入都可以在这种情况下帮助其他人。我读过其他人用唯一 ID 命名文件,通过默默无闻来创建安全性,但这不会在我的情况下减少它,对于任何试图确保安全的人来说,这可能不是最佳实践。

采纳答案by Geoff Appleford

The best way to serve your images is to generate a url using the PHP SDK. That way the downloads go directly from S3 to your users.

提供图像的最佳方式是使用 PHP SDK 生成 url。这样下载就可以直接从 S3 发送给您的用户。

You don't need to download via your servers as @mfonda suggested - you can set any caching headers you like on S3 objects - and if you did you would be losing some major benefits of using S3.

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

However, as you pointed out in your question, the url will always be changing (actually the querystring) so browsers won't cache the file. The easy work around is simply to always use the same expiry date so that the same querystring is always generated. Or better still 'cache' the url yourself (eg in the database) and reuse it every time.

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

You'll obviously have to set the expiry time somewhere far into the future, but you can regenerate these urls every so often if you prefer. eg in your database you would store the generated url and the expiry date(you could parse that from the url too). Then either you just use the existing url or, if the expiry date has passed, generate a new one. etc...

显然,您必须将到期时间设置为遥远的未来,但如果您愿意,可以每隔一段时间重新生成这些 url。例如,在您的数据库中,您将存储生成的 url 和到期日期(您也可以从 url 解析)。然后你要么只使用现有的 url,要么,如果过期日期已过,生成一个新的。等等...

回答by Wes

You can use bucket policies in your Amazon bucket to allow your application's domain to access the file. In fact, you can even add your local dev domain (ex: mylocaldomain.local) to the access list and you will be able to get your images. Amazon provides sample bucket policies here: http://docs.aws.amazon.com/AmazonS3/latest/dev/AccessPolicyLanguage_UseCases_s3_a.html. This was very helpful to help me serve my images.

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

The policy below solved the problem that brought me to this SO topic:

下面的政策解决了让我进入这个 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/*"
          ]
        }
      }
    }
  ]
}

回答by catalinux

When you talk about security and protecting data from unauthorized users, something is clear: you have to check every time you access that resource that you are entitled to.

当您谈论安全性和保护数据免受未经授权的用户访问时,有一点很清楚:您必须在每次访问您有权访问的资源时进行检查。

That means, that generating an url that can be accessed by anyone (might be difficult to obtain, but still...). The only solution is an image proxy. You can do that with a php script.

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

There is a fine article from Amazon's blog that sugests using readfile, http://blogs.aws.amazon.com/php/post/Tx2C4WJBMSMW68A/Streaming-Amazon-S3-Objects-From-a-Web-Server

亚马逊博客中有一篇很好的文章,建议使用 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');

回答by mfonda

You can download the contents from S3 (in a PHP script), then serve them using the correct headers.

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

As a rough example, say you had the following in image.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);

Then in your HTML code, you can do

然后在你的 HTML 代码中,你可以做

<img src="image.php">