Securing AWS S3 URL

How to Secure AWS S3 Object URL

Hi Readers, 
If you are new to AWS S3 then let me brief you about S3 first,


S3 was the very first service of AWS. AWS S3 is object storage. You can store objects like images, pdf, doc, txt .. etc files.

How to Upload Files to AWS S3

I have written tutorial on how to upload your file. Click Here have a look, in case you are interested.

Now lets come to our point. In general you need url to access object uploaded to S3. This URL is like

S3 Object Access URL = https://s3-ap-southeast-1.amazonaws.com/< your bucket name >/< your object name >

By default this url is private. This means that only account owner has access to that after login.
If I will make that object public then it will be accessible to everyone and i don't want to do that. In fact I want that only allowed people can have access to this object.

One way of doing that is to add new permissions per user. In this way that user needs to have AWS account. Also if there are many users and permission allocation is dynamic then this approach is not suited.

A good approach is to make a pre-signed url of the object. User who has this pre-signed url will only be allowed to access object.
I can also give expiration time with this url, by this means we can time access of S3 object. 

Code for generating Signed URL for S3 object

In this tutorial i assume few things
  • You have AWS account
  • You have created S3 bucket
  • You have stored one dummy object to that bucket with default ACL.
  • You have imported AWS Java SDK into your project.
To generate pre-signed url create class like

package com.techiekunal.awss3samples.utils;

import java.io.IOException;
import java.net.URL;

import com.amazonaws.AmazonClientException;
import com.amazonaws.AmazonServiceException;
import com.amazonaws.HttpMethod;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.GeneratePresignedUrlRequest;

public class GeneratePreSignedUrl {
 private static String bucketName = "<bucket name>";
 private static String objectKey = "<Object name or key>";

 public static void main(String[] args) throws IOException {
  AmazonS3 s3client = new AmazonS3Client(new BasicAWSCredentials("<Your AWS Access Key>", "<Your AWS Secret>"));

  try {
   System.out.println("Generating pre-signed URL.");
   java.util.Date expiration = new java.util.Date();
   long milliSeconds = expiration.getTime();
   milliSeconds += 1000 * 60 * 60; // Add 1 hour.

   GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucketName, objectKey);

   URL url = s3client.generatePresignedUrl(generatePresignedUrlRequest);

   System.out.println("Pre-Signed URL = " + url.toString());
  } catch (AmazonServiceException exception) {
   System.out.println("Caught an AmazonServiceException, " + "which means your request made it " + "to Amazon S3, but was rejected with an error response " + "for some reason.");
   System.out.println("Error Message: " + exception.getMessage());
   System.out.println("HTTP  Code: " + exception.getStatusCode());
   System.out.println("AWS Error Code:" + exception.getErrorCode());
   System.out.println("Error Type:    " + exception.getErrorType());
   System.out.println("Request ID:    " + exception.getRequestId());
  } catch (AmazonClientException ace) {
   System.out.println("Caught an AmazonClientException, " + "which means the client encountered " + "an internal error while trying to communicate" + " with S3, " + "such as not being able to access the network.");
   System.out.println("Error Message: " + ace.getMessage());

By running it you will have singed url printed on IDE console. Hit that url and you will have access to your object.
Hit that url again after expiration time, that object should not be accessible to you.
Also if your change few things with that url, it will not work. Nobody will have direct access to that object.

So we have seen a secure way to access S3 objects and only users with url have access to object, also for given expiration time.