Saving images in AWS from backend - amazon-web-services

We need to save product's images in AWS. There are 2 ways, it can be uploaded from frontend(website or mobile application) or from backend.
On frontend side we need to store AWS credentials, which can be an issue. So, we want to go with upload on AWS from backend. The flow will be: user select an image, and upload it to backend, and backend upload it to AWS.
Is this ok? What issues can appear?

There is nothing wrong with uploading it to your backend, presumably an ec2 instance, and then having the ec2 instance upload the file to s3 - thats a secure way of doing it and a method I often use.
However, you do not need to expose your aws credentials to the browser if you would prefer to do the upload directly from your browser to s3 - you would just need to add AWS Cognito to the equation.
Using cognito you can get temporary credentials that will allow you to do the upload without compromising security.
https://aws.amazon.com/sdk-for-browser/

You can also used a pre-signed S3 URL (see: Uploading Objects Using Pre-Signed URLs) which you generate in the backend and pass to the frontend app. Then the flow would be something like this:
Request a pre-signed URL from your backend service
The frontend app PUTs the file to the signed URL
Signing the URL on the backend would look something like this (Ruby):
s3 = Aws::S3::Resource.new(region: 'us-east-1')
url = s3.bucket('my-bucket').object('name-of-file').presigned_url(:put)
And on the frontend you could simply do something like this using fetch:
fetch(signedUrl, { method: 'PUT', body: file })

Related

How to enable presigned S3 URL for different users?

I am trying to build a service where users are able to upload photos to an S3 database using presigned URLs given to them via API gateway. For each user, I was planning on submitting the photo information through the presigned URL and identifying the user who sent it as metadata via the ID found in the access token granted by AWS Cognito.
However, I am not sure how to secure it so that users can only upload photos as themselves and not as others. It seems to me that malicious users can simply modify the frontend code to change the user ID and submit photos as someone else.
I'm wondering if it is possible to create a presigned URL with some sort of ID so that they can only submit content as themselves? Or is there a better way?
How about this solution:-
There is one question that is not mentioned, how do you plan to differentiate legit users and non-legit users, or is it open to everyone?
Use Amazon Cognito to authenticate users.
users will try to query for URL (upload s3 through an interface), API gateway will verify authentication.
if authentication is successful; then only lambda will generate an s3 resigned URL.
This solution is a little costly however it serves you the purpose of making it secure, where if the user is authenticated then only lambda will generate a signed URL.
You should not worry about the identity of the user, or someone sending a false identity, because a sub claim will be present as part of the token, if someone tries to change that, the cognito will not verify it.
A heads up:- if you are trying to make this service global, then you can implement a backend database like dynamodb, and add a manual/automatic step to add a attribute to identity users who are privileged and add logic to lambda to find users who is privileged and then generate resigned URL exclusively for that privileged user
.https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-integrate-with-cognito.html, https://docs.aws.amazon.com/apigateway/latest/developerguide/apigateway-enable-cognito-user-pool.html

How Do I Access S3 Bucket Files in Browser Using AccessKeyId and SecretAccessKey?

I have accessKeyId and secretAccessKey for AWS S3 bucket. How do I access the video files on the bucket using the browser?
I'm using React and Node(Nest.js). I would like to play the video files on the React Frontend
If your web page has AWS credentials, then you can use the AWS JavaScript SDK in the browser to create a pre-signed URL for the video file in S3, then provide that URL to your video player.
If the web page doesn't have AWS credentials and can't easily get them, then consider using AWS Amplify or write a small server-side component to do this on behalf of your client.
Note that pre-signed URLs have an associated expiration date/time.

secure aws s3 objects (control access with authorizer like jwt, how a web app would normally do)

I need to secure my s3 bucket objects. In my web application I'm using aws-sdk to upload media to s3 bucket and get an http link back to access that object. This http link is public by default and I want to make it secure so that only authorized users can access the media. aws s3 allows to make the object private but it wont let anyone with the link access the object.
This link will be accessed from a mobile app where I dont want to use aws-sdk, Instead I want to execute some logic on aws side whenever someone tries to access the http link for the object.
What I would like to happen is, before the user gets access to s3 object, Some authorizer code would execute (like a jwt token authorizer) and depending on it user would be granted/denied access.
I'm currently looking into Amazon API Gateways, I believe they can be accessed as an http link and AWS Lambda could be used to secure them(where i would execute my jwt authorizer). Then these apis would have access to s3 internally.
If someone could point me in the right direction, If this is at all possible.
If I could use the same jwt token issued from my web-application to send along the request to Amazon API Gateway, that would be great.
I would make the bucket private, and place a CloudFront distribution in front of it. Using an Origin access identity to allow only CloudFront to directly access the S3 bucket.
Then to provide security I would use either CloudFront signed cookies, or Lambda#Edge with a custom JWT token validation.
The easiest solution to expose private objects in an S3 bucket is to create a pre-signed URL. Pre-signed URLs use the permissions from the service (which pre-signs the URL) to determine access and have only a limited duration in which they can be used. They can also be used to upload an object directly to S3 instead of having to proxy the upload through a lambda function.
For a download functionality and a smooth user experience, you can - for example - have a lambda function that generates a pre-signed URL and returns it as an HTTP 302 response, which should instruct the browser to automatically download the file from the new URL.
(Edit)
Following on what I've stated in the comments on this answer, if you're proxying the upload/download of the objects through services such as API Gateway or Lambda, you will be severely limited in the size of files that you are able to upload to S3. The payload size limit on an API Gateway is 10 MB and for requests to lambda your payload is capped at 6MB for synchronous invocations. If you want to upload something larger than 10 MB, you will need to use direct upload to S3 for which pre-signed URLs are the safest solution.
I know I am bit late here, but I wanted to give my opinion in case someone has the same problems.
Your mobile app should communicate with a server app (backend app) for authentication and authorization. let's say you are deploying your server app on AWS VPC. Now, it's simple to manage the files access by creating a policy which allow just your server app (IP, or VPC) to access the bucket. the authorization part will be managed on your application.

how to secure HLS streaming using AWS for mobile devices?

We have some videos in an S3 bucket. they've been transformed using AWS Elastic Transcoder to .m3u8 / .ts
We want the users to be able to stream these videos on both a web app and a mobile app.
Now, we want to secure this streaming, so our videos won't get pirated.
So, our proposed solution is as follows:
Prevent public access to the S3 bucket
create a cloudfront distribution with the bucket as the origin
Only enable access to this CDN using pre-signed URLs/cookies
For web app: use a pre-signed cookie (set by an endpoint at our backend that requires authentication), so that it works well with HLS (since the app needs to fetch a new segment every few seconds)
But now we don't know what to do with our mobile app. We can't use pre-signed cookies since there's no browser, and we can't use pre-signed URLs, since we'll need a signed URL for each segment we need to fetch. Any suggestions and solutions are welcome.
For our similar use-case:
We used CloudFront url and not S3 signed url. Because S3 signed URL is valid at object level and not folder level.
For paid videos, security and access was managed by Lambda#Edge on viewer requests.
Although we used OAuth and database inside that lambda, but surprisingly, we didn't face any bottlenecks on Lambda#Edge. For future plans we considered using Redis for seamless access validation inside Lambda#Edge.

Website architecture using auth0, AWS and server

Building my first full stack website. I have an architecture doubt.
What I have:
golang backend
react frontend
auth0 authentication
aws amplify
I am considering to create this architecture, I think that I am misleading with something. The front-end connect direct with s3 bucket to put private images there, but I am not sure if I should do it direct or send the request to my server and then the server update the s3. Searching for solutions, it seams that amplify is great for serverless, but in my application should I change amplify for cloudfront?
You can upload directly from frontend. But make sure you are sanitizing the files you upload. The downside is you will have to add you AWS S3 access credentials in frontend.
If you do it through your server, which I assume to be an AWS service you can give access to S3 for that service through IAM and no credentials required to be stored. And the downside here is an additional hop and latency while uploading big files.
It's a choice for you to make based on your requirements now.