Use case: We are developing a web application and the client has requested us to use AWS S3 to store the images. In the application, Everyone will have their own account and would upload their own images, some of the uploaded images will be public.
According to my understanding we can achieve this by using pre-singed URLs, to upload the images. But the problem that I am facing is, how to restrict access to the images to the other users.
There are two basic ways to use Amazon S3:
- Use it purely as a storage medium, only accessed by your application, or
- Use it to serve content directly to end-users
In the first case, only your application has access to the data/files stored in S3. It must retrieve the content and serve it to users. This is a traditional approach for web servers.
In the second case, you can generate HTML pages that contain references to files stored in S3. For example, if an image appears within a web page, the src=
parameter would point to an Amazon S3 URL. The file is then served from S3 without going via your web server.
This can be enhanced by using Pre-Signed URLs, which are time-limited URLs that provide access to private content stored in Amazon S3. It works like this:
- The files are stored in S3 and are kept private (meaning no access permitted)
- Your application is fully responsible for determining which users can access which files
- When the application wishes to grant access to a user (eg they might want to view their own photos), it generates a Pre-Signed URL and includes this in the HTML page
- When the user's web browser uses the Pre-Signed URL to access content
- Amazon S3 receives the request, verifies the signature and timestamp on the Pre-Signed URL and, if approved, provides the file in response to the request
A Pre-Signed URL consists of:
- A reference to the object requested
- The Access Key associated with an IAM (Identity and Access Management) entity that has permission to access the object -- for example, you could create an IAM User that has the necessary permissions, and then provide these access credentials to your application
- An expiry timestamp until which the Pre-Signed URL is valid
- A cryptographically-calculated signature that verifies that the Pre-Signed URL was created by the entity that owns the Access Key (effectively, it verifies the password and hashes the above information)
The Pre-Signed URL can be created in just a couple of lines of code and does not require a call to the AWS API.
Bottom line: Keep all images private. Your application confirms each user's right to access the images on-the-fly, then generates URLs to grant time-limited access.
You can use signed urls and signed cookies for serving private content. Using private links may not be viable if you can't change the app, signed cookies can help there. Also, CloudFront offers further security and efficiency improvements, check the docs at http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/PrivateContent.html
If you are planning to implement fine-grained access control, there are multiple approaches you can follow. As the first step, you need to have unique spaces for each user to upload content. This can be buckets or path prefix(Which you see as directories) in buckets.
Generally I would recommend to partition the user space with a path prefix for each user, which will allow you to use IAM roles or create pre-signed URLs with required fine-grained access control so that a particular user can access their own space.