Security concern in direct browser uploads to S3 - amazon-web-services

The main security concern in direct js browser uploads to S3 is that users will store their S3 credentials on the client side.
To mitigate this risk, the S3 documentation recommends using a short lived keys generated by an intermediate server:
A file is selected for upload by the user in their web browser.
The user’s browser makes a request to your server, which produces a temporary signature with which to sign the upload request.
The temporary signed request is returned to the browser in JSON format.
The browser then uploads the file directly to Amazon S3 using the signed request supplied by your server.
The problem with this flow is that I don't see how it helps in the case of public uploads.
Suppose my upload page is publicly available. That means the server API endpoint that generates the short lived key needs to be public as well. A malicious user could then just find the address of the api endpoint and hit it everytime they want to upload something. The server has no way of knowing if the request came from a real user on the upload page or from any other place.
Yeah, I could check the domain on the request coming in to the api, and validate it, but domain can be easily spoofed (when the request is not coming from a browser client).
Is this whole thing even a concern ? The main risk is someone abusing my S3 account and uploading stuff to it. Are there other concerns that I need to know about ? Can this be mitigated somehow?

Suppose my upload page is publicly available. That means the server
API endpoint that generates the short lived key needs to be public as
well. A malicious user could then just find the address of the api
endpoint and hit it everytime they want to upload something. The
server has no way of knowing if the request came from a real user on
the upload page or from any other place.
If that concerns you, you would require your users to login to your website somehow, and serve the API endpoint behind the same server-side authentication service that handles your login process. Then only authenticated users would be able to upload files.
You might also want to look into S3 pre-signed URLs.

Related

How to use the TranscribeStreamingClient in the browser with credentials

I want to be able to offer a RT transcription in my browser app using AWS transcribe. I see there is the TranscribeStreamingClient which can have credentials for AWS which are optional - I assume these credentials are required for access to the s3 bucket?
What I want to know is how to setup auth in my app so that I can make sure my users dont go overboard with the amount of minutes they transcribed?
For example:
I would be expecting to generate a pre-signed url that expires in X seconds/minutes on my Backend that I can pass to the web client which it then uses to handle the rest of the communication (similar like S3).
However I don't see such an option and the only solution that I keep circling back to is that I would need to be feeding the audio packets from to my backend which then handles all the auth and just forwards it to the service via the streaming client there. This would be okay but the documentation says that the TranscribeStreamingClient should be compatible for browser integrations. What am I missing?

serving user content/images from amazon s3

I am building an app which lets users upload pictures and share it with his/her friends only.
I am using spring restful services to upload content directly to s3.
The user is authorized using OAuth.
To upload an image an authorized user's js client invokes POST /images/{userid}
To download the image, the client has to invoke GET /images/{userid}/{imageid}
Each user's content is stored in s3 under his own folder name, and the downloading service as explained in point 4 is the one that has to be invoked. Unfortunately, this means I cannot assign this url as source to an image tag <img src="">, because the authorization token should be sent on GET request. I cannot make the contents of user folder public because only user and his friends are allowed to see the images. The current service will soon become a bottleneck and I would like to avoid that.
What is the recommended architecture/design to solve this problem?
Instead of having a service that loads and returns the entire image file from S3, you should have a service that simply generates an S3 presigned URL. Then the URL retrieved from that service can be used in the <img src=""> tags on your site. This will be much more performant since the web browser will ultimately download the image directly from S3, while also still being secure.
The flow for downloading the images would be like this
User invokes GET request to download image
At Server End
Authenticate user
Query DB for metadata
Create a time based auth token.
Create a image URL(S3 based) and append auth token created in previous step
At the client end(User browser) redirect user to new URL(this url is effectively S3 location+auth token )
Now direct request will comes at the server( image URL+ auth token)
authenticate the token and then show image to user
Above URL will not be valid for long time , but your images are secured. As auth token is time based it will cater your case like if some one make the image private/public remove a friend.Deleted images , Copy paste of image url etc ..

Is it a bad practice to make request to 3rd party service to get token?

Suppose this scenario:
I'm building service which works with user uploads to my AWS S3 account.
Each site using my service must have upload form which uploads directly to S3. In order to do that each site has to sign it's upload form with AWS Signature Version 4.
The problem is signing requires AWSAccessKeyId and AWSSecretAccessKey which i must share to my service user and that's not acceptable.
I thought i can generate all needed signing data on my side and the just reply with that when user(site) asks for it.
So the question is: is that a bad idea in order to sign upload form site(which is going to upload file to my S3) has to make request to my server for signing data(XHR or server side)?
I'm not entirely sure what you're asking, but if you're asking if it's a bad idea to sign the upload yourself on behalf of the individual sites, than the answer is no...with a caveat.
Signing the upload (really, you should just sign the upload URL) is far less of a security risk than providing other domains your access keys. That's what it's there for, to allow anonymous uploads. Signing the request merely gives the site/user permission to upload, but does not take into account who is uploading or what they are uploading.
This is where your own security checks need to come in. If the form is hosted on multiple domains (all uploading to your S3 bucket), you should first check the domain the form originated from so as to avoid someone putting the form on their own webserver and trying to upload stuff. Depending on how your various sites are configured, there are a couple of ways to do this, of which I am no expert unfortunately.
Secondly, you will want to validate the data being uploaded. Is it pure text, binary, etc.? You will want to validate all of that prior to initiating the upload.
I hope this helps.

security in serving private content s3 + cloudfront + signed URL

I've read aws docs about using s3 + cloudfront + signed URL architecture to securely serve private content to public users. However it seems not secure enough to me. Let's me describe in steps:
Step 1: user logs in to my website.
Step 2: user clicks download (pdf, images, etc.)
Step 3: my web server will generate signed URL (expiry time: 30 secs), redirect user to the signed url and the downloading process happens.
Step 4: now, even though it's timed out after 30 secs, there is still a chance that any malicious snipper on my network will be able to catch the signed url and download my user's private content.
Any thought for this?
The risks you anticipate exist no matter what mechanism you use to "secure" anything on the web, if you aren't also using HTTPS to encrypt your users' interactions with the web site.
Without encryption, the login information, or perhaps cookies conveying the user's authentication state are also being sent in cleartext, and anything the user downloads can be directly captured without need for the signed link... making concern about capturing a download link via sniffing seem somewhat uninteresting compared to the more significant risk of general and overall insecurity that exists in such a setup.
On the other hand, if your site is using SSL, then when you deliver the signed URL to the user, there's a reasonable expectation that it will be hidden from snooping by the encryption... and, similarly, if the link to S3 also uses HTTPS, the SSL on that new connection is established before the browser transmits any information over the wire that would be discoverable by sniffing.
So, although it seems correct that there are potential security issues involved with this mechanism, I would suggest that a valid overall approach to security for user interactions should reduce the implications of any S3 signed URL-specific concerns down to a level comparable to any other mechanism allowing a browser to request a resource based on possession of a set of credentials.

privacy on Amazon S3

I have an app that lets users post and share files, and currently it's my server that serves these files, but as data grows, so I'm investigating using Amazon S3. However, I use dynamic rules for what is public and what is private between certain users etc, so the server is the only possible arbiter, i.e. permissions cannot be decided on the app/client end.
Simplistically, I guess I can let my server GET data from S3, then send them back to the app. But obviously then I'm paying for bandwidth twice not to mention making my server do unnecessary work.
This seems like a fairly common problem, so I wonder how do people typically solve this problem? (Like I read that Dropbox stores its data on S3.)
We have an application with pretty much the same requirements, and there's a really good solution available. S3 supports signed, expiring S3 URLs to access objects. If you have a private S3 object that you, but not others, can access, you can create such a URL. If you give that URL to someone else, he or she can use it to fetch the object that they normally have no access to.
So the solution for your use case is:
User does a GET to the URL on your web site
Your code verifies that the user should be able to see the object (via your application's custom, dynamic rules)
The web site returns a redirect response to a signed S3 URL that expires soon, say in 5 minutes
The user's web browser does a GET to that signed S3 URL. Since it's properly signed and hasn't yet expired, S3 returns the contents of the object directly to the user's browser.
The data goes from S3 to the user without ever traveling back out through your web site. Only users your application has authorized can get the data. And if a user bookmarks or shares the URL it won't work once the expiration time has passed.