Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails implementation for securing S3 documents

I would like to protect my s3 documents behind by rails app such that if I go to:

www.myapp.com/attachment/5 that should authenticate the user prior to displaying/downloading the document.

I have read similar questions on stackoverflow but I'm not sure I've seen any good conclusions.

From what I have read there are several things you can do to "protect" your S3 documents.

1) Obfuscate the URL. I have done this. I think this is a good thing to do so no one can guess the URL. For example it would be easy to "walk" the URL's if your S3 URLs are obvious: https://s3.amazonaws.com/myapp.com/attachments/1/document.doc. Having a URL such as: https://s3.amazonaws.com/myapp.com/7ca/6ab/c9d/db2/727/f14/document.doc seems much better. This is great to do but doesn't resolve the issue of passing around URLs via email or websites.

2) Use an expiring URL as shown here: Rails 3, paperclip + S3 - Howto Store for an Instance and Protect Access For me, however this is not a great solution because the URL is exposed (even for just a short period of time) and another user could perhaps in time reuse the URL quickly. You have to adjust the time to allow for the download without providing too much time for copying. It just seems like the wrong solution.

3) Proxy the document download via the app. At first I tried to just use send_file: http://www.therailsway.com/2009/2/22/file-downloads-done-right but the problem is that these files can only be static/local files on your server and not served via another site (S3/AWS). I can however use send_data and load the document into my app and immediately serve the document to the user. The problem with this solution is obvious - twice the bandwidth and twice the time (to load the document to my app and then back to the user).

I'm looking for a solution that provides the full security of #3 but does not require the additional bandwidth and time for loading. It looks like Basecamp is "protecting" documents behind their app (via authentication) and I assume other sites are doing something similar but I don't think they are using my #3 solution.

Suggestions would be greatly appreciated.

UPDATE:

I went with a 4th solution:

4) Use amazon bucket policies to control access to the files based on referrer: http://docs.amazonwebservices.com/AmazonS3/latest/dev/index.html?UsingBucketPolicies.html

UPDATE AGAIN:

Well #4 can easily be worked around via a browsers developer's tool. So I'm still in search of a solid solution.

like image 542
Arthur Frankel Avatar asked Jun 18 '11 22:06

Arthur Frankel


1 Answers

You'd want to do two things:

  1. Make the bucket and all objects inside it private. The naming convention doesn't actually matter, the simpler the better.

  2. Generate signed URLs, and redirect to them from your application. This way, your app can check if the user is authenticated and authorized, and then generate a new signed URL and redirect them to it using a 301 HTTP Status code. This means that the file will never go through your servers, so there's no load or bandwidth on you. Here's the docs to presign a GET_OBJECT request:

https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/S3/Presigner.html

like image 51
Sudhir Jonathan Avatar answered Sep 24 '22 10:09

Sudhir Jonathan