0

I'm attempting to lock down viewing of S3 resources - really just images - to my web application's domain. For instance, if someone goes to my site - let's say example.com - and there's a src reference to the image, I want it to be viewable. But if someone were to right click and open up the image directly in a new tab, they shouldn't be able to.

There's tons on the web out there, but I just can't seem to find the correct combination or permissions. And most tutorials don't usually talk about the "Block Public Access" settings, and I'm not sure how that fits in.

Here's the policy I'm attempting:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Allow get requests originating from example.com",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::my-bucket",
            "Condition": {
                "StringLike": {
                    "aws:Referer": [
                        "https://www.example.com/*"
                    ]
                }
            }
        },
        {
            "Sid": "Do not allow requests from anywhere else.",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::my-bucket",
            "Condition": {
                "StringNotLike": {
                    "aws:Referer": [
                        "https://www.example.com/*"
                    ]
                }
            }
        }
    ]
}

This doesn't seem to do anything. If "block public access" is on, both are blocked. If it's off, both are shown. That is, even though I have an explicit "Deny" list above, going right to the image on that bucket in the browser works fine.

I can also edit CORS, but I'd still then wonder why the deny list here wouldn't take care of that itself. Finally, after implementing the policy, I lose lots of abilities myself, such as setting CORS, even when using the root user account. I can probably just do things in a different order to make it happen, but I'd like to still be able to manage my permissions after submitting the policy.

enter image description here

Thanks.

Jeremy L.
  • 853
  • 8
  • 15

1 Answers1

1

Step 1: Block all public access should be disabled to apply the bucket policy settings, You can make your block all public settings as shown in the above image.

S3 access block settings

Step 2: Organize all your website images in to one folder like “images”

Step 3: Setup a bucket policy as below. It has two statements. Statement 1 denies images folder to all except from your domain. Statement 2 allows everything. Since deny overwrites allow, statement 1 has more power than statement 2 hence it blocks images which calling from outside of your domain.

{ 
"Version": "2012-10-17", 
"Id": "http referer policy example", 
"Statement": [ 
    { 
        "Sid": "Deny get requests not originating from www.example.com and example.com.", 
        "Effect": "Deny", 
        "Principal": "*", 
        "Action": "s3:Get*", 
        "Resource": "arn:aws:s3:::your-bucket/images/*", 
        "Condition": { 
            "StringNotLike": { 
                "aws:Referer": [ 
                    "http://www.example.com/*", 
                    "http://www.example.com/" 
                ] 
            } 
        } 
    }, 
    {
        "Sid": "Allow get requests", 
        "Effect": "Allow", 
        "Principal": "*", 
        "Action": "s3:Get*", 
        "Resource": "arn:aws:s3:::your-bucket/*" 
    } 
] }

Step 4: You have to change your front end code a little bit, wherever you are using image tags you need to add “referrerpolicy” set to “origin”, if you don’t set this field referer header won’t be forwarded to S3 and rule evaluation failed and 403 will occur.

Example: <img src="images/pic_trulli.jpg" alt="Trulli" width="500" height="333" referrerpolicy="origin">

This solution is tested and working. If you also need CORS, you can enable CORS on S3 bucket as well. But this policy is good enough to handle.

When calling with domain -->

enter image description here

When calling with S3 URL -->

enter image description here

If this solution helps you, mark it as answered.

  • Hi @Rakeshkumar, thank you! I'll be testing this out. Can you tell me, why is it necessary to specifically allow GET requests if public access isn't blocked? The first rule would block outside domains from getting access, but I don't see anything that would block my own domain from doing so. – Jeremy L. Jun 02 '22 at 16:18
  • In S3/AWS, everything is private until you make them public. Hence, we are allowing GET requests. 2nd rule allowing everything and the 1st rule denying all other domains except yours. In this way, it allows only your domain to access images folder. – Rakeshkumar Taninki Jun 03 '22 at 10:54
  • Hmm I don't think that's the case. Right now, before these changes, everything is public on this bucket, and there is no policy. Perhaps it's something like "*if there's a policy*, everything is private unless you explicitly mark it public." – Jeremy L. Jun 03 '22 at 15:26
  • what about background image url's? I don't see a way to set the referrer policy there. – Jeremy L. Jun 20 '22 at 19:03
  • I'm finding that referral policy isn't required at all to send the referer header, on a background image or an image from an img tag. Maybe on a specific, older browser? In any case, it works! My confusion about the "private until you make it public" was because the individual objects in my buckets were marked readable by the public. So for anyone reading, if you don't have "block public access checked", while things are private until you mark them public, just realize that individual items can be marked public too, not just the bucket. – Jeremy L. Jun 20 '22 at 20:13