简体   繁体   English

来自 URL referer 的 AWS S3 Bucket 策略/访问 - 访问被拒绝

[英]AWS S3 Bucket policy/access from URL referer - access denied

My problem is maybe trivial, but I can't find the good example or straight answer anywhere...我的问题可能是微不足道的,但我无法在任何地方找到好的例子或直接的答案......

My setup:我的设置:

  • Web app client written using Apollo and ReactJS Web 使用 Apollo 和 ReactJS 编写的应用程序客户端
  • Server/API written using Apollo, ReactJS and GraphQL使用 Apollo 编写的服务器/API,ReactJS 和 GraphQL
  • Database: Mongoose数据库:Mongoose

What I want to achieve:我想要实现的目标:

I want to upload files via browser using my application straight to Amazon S3 bucket and have the ability to later list those files with thumbnails (if those are images) in the app.我想使用我的应用程序通过浏览器将文件直接上传到 Amazon S3 存储桶,并能够稍后在应用程序中列出这些带有缩略图(如果是图像)的文件。

I have everything setup nicely when it comes to uploading to S3.在上传到 S3 时,我的一切设置都很好。 I'm using AWS JS SDK, have setup API key and secret, all in all, good.我正在使用 AWS JS SDK,设置了 API 密钥和秘密,总而言之,很好。

The problem:问题:

Everything works properly as long as my bucket is completely public .只要我的存储桶是完全公开的,一切都会正常进行。 But of course I don't want it to be public.但我当然不希望它公开。 This app will be for company internal use only, files or anything, can't be available to the public...此应用程序将仅供公司内部使用,文件或任何东西,不能对公众开放...

When I switch of public access to the bucket, I'm not longer able to even upload the files through my app, needless to say, I'm not able to see the files in my app...当我切换到存储桶的公共访问权限时,我什至无法再通过我的应用程序上传文件,不用说,我无法在我的应用程序中看到这些文件......

I was trying to implement some bucket policy, that would allow files to be uploaded or seen if the referrer came from one of the IP addresses that I use to reach my app in the browser, but that did not work at all... (IP addresses shown in my policy below are not the one I'm using of course, I change them here for privacy)我试图实施一些存储桶策略,允许上传文件或查看引荐来源网址是否来自我用来在浏览器中访问我的应用程序的 IP 地址之一,但这根本不起作用...... (下面我的政策中显示的 IP 地址当然不是我使用的 IP 地址,我在这里更改它们以保护隐私)

{
    "Version": "2012-10-17",
    "Id": "http referer policy example",
    "Statement": [
        {
            "Sid": "Allow get requests originating from 1.1.1.1:3000",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "*",
            "Resource": "arn:aws:s3:::escape-dam/*",
            "Condition": {
                "StringLike": {
                    "aws:Referer": "http://1.1.1.1:3000/*, http://1.1.1.1:4000/*, http://2.2.2.2:3000/*, http://2.2.2.2:4000/*"
                }
            }
        }
    ]
}

Dream solution:梦想解决方案:

Policy written in such a way, that my app will be able to send and receive files from S3 Bucket, without having to authorise each request.以这种方式编写的策略,我的应用程序将能够从 S3 存储桶发送和接收文件,而无需授权每个请求。 Basically, if you want to upload or request the file through the app you're allowed to, but not when trying to copy and paste the URL into the browser.基本上,如果您想通过应用程序上传或请求文件,您可以这样做,但在尝试将 URL 复制并粘贴到浏览器时则不行。

As an addition I have to state, that because this is an ReactJS app, it does not ask for the files from S3 Bucket itself.作为补充,我必须使用 state,因为这是一个 ReactJS 应用程序,它不会从 S3 Bucket 本身请求文件。 It passes the stored URI from the database to the client side of the app, which later gets rendered with the page itself, so not the server asks S3 for the file, but the user's browser does.它将存储的 URI 从数据库传递到应用程序的客户端,稍后将与页面本身一起呈现,因此不是服务器向 S3 请求文件,而是用户的浏览器请求。 I hope this clarify my problem in it's entirety;)我希望这能完整地阐明我的问题;)

I hope I'm clear here and do not overstate something trivial, but I'm pretty new when it comes to dealing with S3我希望我在这里很清楚,不要夸大一些琐碎的事情,但在处理 S3 方面我还是个新手

Thank you in advance for any help!预先感谢您的任何帮助!

Since you want to upload from the frontend (client's browser) directly to your S3 bucket, the best solution is to use S3 SignedURL feature.由于您想从前端(客户端的浏览器)直接上传到您的 S3 存储桶,最好的解决方案是使用 S3 SignedURL 功能。

Uploading files: The way it works (roughly) is to have your backend services send an upload request to S3, which then generates an upload URL (with a POST or PUT method).上传文件:它的工作方式(大致)是让您的后端服务向 S3 发送上传请求,然后 S3 生成上传 URL(使用 POST 或 PUT 方法)。 The backend service returns this URL to the frontend client, who can then upload directly to S3.后端服务将此 URL 返回给前端客户端,然后前端客户端可以直接上传到 S3。 Cost reduction and better performance (especially with transfer acceleration) are just some of the benefits.成本降低和更好的性能(尤其是传输加速)只是其中的一些好处。

Downloading files: The backend service generates and returns this URL to the frontend client, who can than use this URL to directly access/download the file.下载文件:后端服务生成并返回这个 URL 给前端客户端,前端客户端可以使用这个 URL 直接访问/下载文件。

So the only way to upload or download the files from S3 is with the signed URL. You can also set the expiration time for each URL (the duration for how long the URL is valid)所以从S3上传或下载文件的唯一方法是使用签名的URL。您还可以为每个URL设置到期时间(URL有效的持续时间)

Best, Stefan最好的,斯特凡

So... Thank you all very much for your input.所以...非常感谢大家的意见。 I've found the solution by combining your answers and further digging into the S3 docs.我通过结合您的答案并进一步深入研究 S3 文档找到了解决方案。

What I'm doing in my policy is: Blocking any IP other than my server and Blocking any referer other than my app URL我在我的政策中所做的是:阻止除我的服务器之外的任何 IP阻止除我的应用程序 URL 之外的任何引用者

Please, check my updated policy below.请在下方查看我更新的政策。 If you also could tell me if this is secure enough, that would be great, As an addition: my bucket public access settings looks like this:如果您还可以告诉我这是否足够安全,那就太好了,另外:我的存储桶公共访问设置如下所示:

Block all public access
 Off
Block public access to buckets and objects granted through new access control lists (ACLs)
 On
Block public access to buckets and objects granted through any access control lists (ACLs)
 Off
Block public access to buckets and objects granted through new public bucket or access point policies*
 On
Block public and cross-account access to buckets and objects through any public bucket or access point policies*
 On
{
    "Version": "2012-10-17",
    "Id": "S3PolicyId1",
    "Statement": [
        {
            "Sid": "IPAllow",
            "Effect": "Deny",
            "Principal": "*",
            "Action": [
                "s3:GetObject",
                "s3:GetObjectVersion"
            ],
            "Resource": [
                "arn:aws:s3:::my-s3-bucket-name",
                "arn:aws:s3:::my-s3-bucket-name/*"
            ],
            "Condition": {
                "StringNotLike": {
                    "aws:Referer": [
                        "http://1.1.1.1:3000/*",
                        "http://1.1.1.1:4000/*",
                        "http://2.2.2.2:3000/*",
                        "http://2.2.2.2:4000/*"
                    ]
                },
                "NotIpAddress": {
                    "aws:SourceIp": [
                        "1.1.1.1",
                        "2.2.2.2"
                    ]
                }
            }
        }
    ]
}

You can use CloudFront + OAI ( origin access identity) with bubket policy that only allows access to OAI, check out policy from docs .您可以将CloudFront + OAI(原始访问身份)与仅允许访问 OAI 的 bubket 策略一起使用, 请从文档中查看策略 In this way request coming from cloudfront can only access your bucket.这样,来自云端的请求只能访问您的存储桶。 another benefit cloudfront offer is caching on edge locations, which improves latency and reduce your cost for number of request on s3 bucket. cloudfront 提供的另一个好处是在边缘位置缓存,这可以改善延迟并降低 s3 存储桶请求数量的成本。

{
    "Version": "2012-10-17",
    "Id": "PolicyForCloudFrontPrivateContent",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity EH1HDMB1FH2TC"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::DOC-EXAMPLE-BUCKET/*"
        }
    ]
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM