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 ..
Related
I am looking for a quick/cheap way to implement the access management of a CDN containing images.
Please check the diagram
context
A user usually requests a high number of small images (latency should be below 200ms), and a user requests images one by one.
access management
A user updates the permission of an image in the DB
A permission hook is triggered and updates the permission file of the image (add user id in the file)
Upload/update the S3 bucket with the new permission file
invalidate CLOUDFRONT cache for this specific file
image request
A user sends an HTTP request to collect an image
METHOD: GET
URL: URL/image-id.png
HEADER: Authorisation (containing user id)
The edge lambda intercepts the request, validates the token, uses the image id to retrieve the permission file of the image, and finally verifies if the file contains the user id.
If any steps in point 2 fail, then the lambda returns an error message; otherwise forward the request to CDN.
What do you guys think? Is it a terrible idea?
I have a webapp and each user can upload images to a private AWS S3 bucket.
In the desired page each user can view his images. Unlike other files (text / csv files etc...), these images should be displayed immediately when the page loads and not downloaded to the local computer one by one.
To display the relevant images to the user I found few ways:
Download the images in the server directly and send them as HTTP response to the user.
Use presigned URLs and if the image is expired a request will be sent to refresh the presigned URL from the server. The new URL will be sent to the user and will be saved in the DB as well that the next time a user requests for the image he has the updated presigned URL.
The first approach is not ideal.
The second approach sounds more efficient, but let's assume a page contains dozens of images that should be displayed and all the presigned URLs have expired. Should I take this approach altough it might end with dozens of requests just for refreshing the presigned URLs? As far as I know it is a problem because there isn't an option the generate presigned URL without expiry (7 days max) and there isn't an option for generating presigned URL for entire directory instead of an object. And what happens to browser caching when presigned URLs are refreshed?
I am wondering what is the best approach for displaying the private images that cannot be shared between users.
Any suggenstions?
Thanks.
I am using s3-bucket to store app config data for multi tenant application. I need tenant info saved in public file(.json) in s3-bucket before client is logged in to the application. For example, app config data might be client logo and some custom title/sub-title for each tenant and etc. I am trying to fetch file content based on sub-domain.
So, I need to fetch the client data, while rendering the login component itself. I am using aws-sdk tool in client side, but am facing 'missing credentials` error.
I am not getting, How to achieve this??
thanks and regards
SHASHIDHAR N K
The AWS SDK for Javascript uses the S3 rest API in such a way that it requires a GET request to be authorized. This is because it uses request parameters to override response header values and for these the rest API documentation for GET says:
Note - You must sign the request, either using an Authorization header or a pre-signed URL, when using these parameters. They cannot be used with an unsigned (anonymous) request.
However, you don't need to use S3 to get a public file, you can make a standard http request using XMLHttpRequest or suchlike.
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.
I've got a Django Rest API and a React Native app. I'd like to upload some files to my s3 bucket from my app.
I could do this :
User would like to upload an image --> GET my_api/s3/credentials/
App --> POST image directly to s3 using credentials (access/private keys)
The problem is that once the user has the accessKey and privateKey, he can use it indefinitely.
Is there a way to retrieve temporary credentials I could give to the user after a call on my_api/s3/credentials/ ?
I've found an answer. It is possible to generate from server side a temporary URL to POST your content.
details here