Accessing files from AWS S3 Bucket - node.js

I am using NodeJS to upload a file into my S3 bucket. As a response I receive a link to the file.
For example I receive https://my-bucket-name.s3.ap-south-1.amazonaws.com/testUpload_s.txt
The bucket does not allow public access as of now. How am I supposed to securely access the file from the bucket? I would like to know whether the the following method be safe?
Allow public access for bucket
Each file will be given a random unique name during upload
This file name or the response URL is stored in the database
When the file has to be fetched I use the link received from the
upload response to access the file from the bucket
Is this approach safe? If not is there any other method to do the same?

There are a number of options for giving clients access to an object in S3, including:
make the object public
require the client to authenticate with AWS credentials
give the client a time-limited, pre-signed URL
They each serve a different use case. Use #1 if it's safe for anyone to access the file (for example the file is an image being shown on a public web site). Use #2 if the client has AWS credentials. Use #3 if you don't want to make the file public but the client does not have AWS credentials. Note with #3 that the pre-signed URL is time-limited.

You don't need to store URL. You can query objects in S3 bucket using file name.
For access from outside Use signed url.
https://docs.aws.amazon.com/sdk-for-go/v1/developer-guide/s3-example-presigned-urls.html

Related

Granting access to user specific images in an s3 private bucket through app

I have a MEAN stack app built where the user can upload images. Currently, I'm storing the URLs of the images in mongodb, and the images themselves in the filesystem in a specified folder. I've read that it's better to store these images somewhere like AWS or firebase for scalability, so I decided to go with AWS.
I created a bucket and can upload images fine via multer.
How can I allow users to only retrieve their images when they are logged into my app? The authentication in the frontend and backend is already finished, but I can't figure out how to use this with accessing the s3 bucket and only getting the user specific images.
I could make the bucket public and easily build the URLs, but that means everyone (regardless if they are logged into my app or not) can access them, which is not what I want.
If you can authenticate your users as Amazon Cognito users then during a login they will assume a role.
If that role has a policy attached for S3 you can use the ${cognito-identity.amazonaws.com:sub} variable. By structuring your S3 bucket to use key paths containing this variable in it you can develop a policy that will only grant access to keys with the prefix of that user id.
Take a look here for an example S3 policy.

Amazon S3 Privacy & Security

We are storing files uploaded by users of our app to Amazon S3.
In order to keep these files private & secure, we are:
having the client generate a UUID for the filename (so that the URL of the file is difficult to guess). See: What is the probability of guessing (matching) a Guid?
going to protect the data by using client-side encryption.
Do these two measures provide sufficient security, or should we also use Amazon Cognito to ensure that the user getting the object is one of the users who has access to it?
Using obscure filenames is not a good security method.
If you wish to allow users to upload/download data to/from Amazon S3 in a secure manner, you should use Pre-Signed URLs.
The process is:
Users authenticate to your web/mobile application
Users interact with your application and indicate they wish to upload/download a file
Your application generates a pre-signed URL that includes an authorization to access Amazon S3, with restrictions such as bucket, path and file size
Users upload/download the file using the pre-signed URL
This way, your application controls the security and there is no potential for accidental workaround, overwriting, access, etc.
See: Uploading Objects Using Pre-Signed URLs

How to use Cloudfront to protect my files

I have a bunch of images on my S3 which is linked with Cloudfront.
Now I have a web server and I only want users to view the image through my website so I can't just give out links to the image. How do I set that?
It appears that your requirement is:
Content stored in Amazon S3
Content served via Amazon CloudFront
Content should be private, but have a way to let specific people view it
This can be accomplished by using Pre-Signed URLs. These are special URLs that only work for a limited period of time.
When your application determines that the user is entitled to view an image, it can generate a Pre-Signed URL that grants access for a limited period of time. Simply use this URL in an <IMG> tag as you would normally.
See:
Amazon S3 pre-signed URLs
Amazon CloudFront pre-signed URLs
Since your content in Amazon S3 will be private (so users cannot bypass CloudFront and access it directly), you will also need to grant CloudFront permission to access the content from S3. See: Using an Origin Access Identity to Restrict Access to Your Amazon S3 Content
Another option, instead of creating a pre-signed URL each time, is to use Signed Cookies. However, this doesn't give fine-grained control for access to individual objects -- it's more for granting access to multiple objects, such as a subscription area.

How can I securely store my AWS keys for an app on AppHarbor?

I am building an app that needs to upload files to S3. Initially, I had my secret key in the web.config file. Since they key has access to my entire account, I am realizing that instead I should rely on the IAM services to just generate a user for accessing a bucket.
However, this doesn't solve the problem of storing the key in plain text. How can I manage it otherwise?
Actually IAM permissions to S3 do solve your problem because the user that you'll create will be only allowed to access this specific bucket - it can't do any harm to your account and you don't have to store the access/secret keys on the machine.
Further, you can restrict access to a bucket to a specific IP.

How to sign Amazon S3 request without providing AWS Credentials?

We have a Java product which may put and get data from Amazon S3. We already successfully implemented a class responsible of that by using the Amazon SDK for Java.
But, as far as I know, to interact with Amazon S3 through the library, you have to instantiate an AmazonS3Clientobject by providing an access key and a secret key.
Even if this technique can be relatively safe by using Amazon IAM and restrict access of the keys to the specific bucket of S3 you want to pull and put data, it is still a security hole in a sense that someone could decompile your application to extract the keys and use them to access your bucket's data.
Is there a safer way to do that ? Can we avoid to embed the AWS credentials in the application ? Can we make a REST call to our server to sign the requests (and keep the keys secret) ?
Take a look at the Amazon Secure Token Service (JavaDoc) as well as the Token Vending Machine to see if these help to resolve your issue.

Resources