Restrict access to the media content

Amazon S3 bucket storage is a real blessing for developers, right? It’s easy to store and access data as per our need from buckets.

But… What if we need to block access to an object from external platforms?

I came across this issue recently. I was storing video files in a public bucket and using those object’s URLs while accessing it.

Now Consider a case where user right clicks and uses “save video as” option provided by browser. User can easily download video file using this option. So my first issue was “Don’t allow users to download video from “save video as” option provided by browsers”

Another possible scenario, if user inspects page and gets the src_url. User can just copy and paste it on browser and bammm…!!! He can download the video. To avoid this I had to block access to the files if user tries to access them from external platforms.

1. First let me tell you how did I eliminated possibility of downloading video using “save video as “ option

After research, it came out that you can not disable “Save Video As” option. But there are few things which can solve this issue.

1.1 Some of the video players help us with the customised context-menu. I was using “videoJs”. It has this feature. You can refer videojs-contextmenu-ui. Using this you can write your own context-menu.

1.2 You can disable right click which indirectly blocks access to “save as” option.

In ReactJs you just have to add this {onContextMenu={(e) => e.preventDefault()} to the div of the page for which you want to disable right click.

Check the example shown below.

return (
  <div onContextMenu={(e) => e.preventDefault()}>
    Right click is disabled for this Page
  </div>
);

Both the options can solve the issue. I went with the second option as there was no need for special context-menu in my case.

2. Now let’s see how can we block access to the files if users access object from external platforms.

You guys must be thinking just make the bucket private and then access object using pre-signed urls. Sounds good right?

Let’s say we have stored some video in our private bucket and we are using pre-signed url. Still user can inspects page and gets the src_url(which will be pre-signed url). Since anyone having pre-signed url can access the object, user can just paste it on browser and download the video.

What to do now? After trying a couple of solutions we finally found the correct way to do it.

Create a public bucket. Go to your bucket. Click on permissions and search for “Block public access (bucket settings)”. Now just check the box in front of the option saying “Block public access to buckets and objects granted through any access control lists (ACLs)”. This will block access to buckets from all the platforms. But still AWS services can access the objects.

Now we just have to update bucket policy to allow our domain to access objects stored in bucket. Scroll down and search for “Bucket policy”. Your bucket policy should look like this:

{
  "Version": "2012-10-17",
  "Id": "PolicyId",
  "Statement": [
    {
     "Effect": "Allow",
     "Principal": "*",
     "Action": "s3:*",
     "Resource": "arn:aws:s3:::bucket-name/*", 
     "Condition": {
	"StringLike": {
	  "aws:Referer": "https://myapp.com/*"
	}
     }
    },
    {
      "Effect": "Allow",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": "arn:aws:s3:::bucket-name/*",
      "Condition": {
	"IpAddress": {
	  "aws:SourceIp": "192.0.2.0/24"
	}
      }
    }
  ]
}

2.1 Do I need to specify both Ip Address and APP URL?

No, You can specify either your app url or IP Address as per your requirements.

In above case both back-end and front-end of my app can access objects from bucket along with AWS services.

2.2 Why are we not setting both StringLike and IpAddress condition in one block itself?

If the bucket policy includes multiple condition keys that result in a logical AND on the other hand Multiple statement blocks results in logic OR which will full-fill our requirements.

Let’s check if everything works fine:-

1. Go to your page and check right click functionality.

2. Check both front-end and back-end can access object

3. Now copy one of your object url and paste it on browser

It should give you error shown below

Image for post

That’s right, it’s this simple. For more information, you can refer access management in Amazon S3.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.