Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to proxy files from S3 through rails application to avoid leeching?

In order to avoid hot-linking, S3 bandwidth leeching, etc I would like to make my bucket private and serve the files through a Rails app. Concept in general sounds very easy, but I am not entirely sure which approach would be the best for the situation.

I am using paperclip for general asset management. Is there any build-in way to achieve this type of proxy?

In general I can easily parse the url's from paperclip and point them back to my own controller. What should happen from this point? Should I simply use Net::HTTP to download the image, and then serve it with send_data? In between I want to log referer and set proper Control-Cache headers, since I have a reverse-proxy in front of the app. Is Net::HTTP + send_data resonable way in this case?

Maybe whole ideas is really bad for some reasons I am not aware at this moment? I general I believe that reveling the direct S3 links to public bucket is dangerous and yield in some serious problems in case of leeching / hot-linking...

Update:

If you have any other ideas which can reduce S3 bill and prevent hot-linking leeching in anyway please share, even if they are not directly related to Rails.

like image 804
mdrozdziel Avatar asked Oct 27 '10 22:10

mdrozdziel


2 Answers

Use (a private bucket|private files) and use signed URLs to the files stored on S3.

The signature includes an expiration time (e.g. 10 minutes from now, whatever you would like to set), as well as a cryptographic hash. S3 will refuse to serve files if the signature is invalid, or if the expiration time has passed.

This is useful because only you can create valid URLs to your private files in S3, and you can control how long the URLs remain valid. This prevents leeching, because leechers can't sign their own URLs and, if they get a URL that you signed, that URL will expire very shortly and after that can not be used.

like image 72
yfeldblum Avatar answered Nov 14 '22 23:11

yfeldblum


Since there wasn't a nuts and bolts answer above, here's a small code sample of how to stream a file that's stored on S3.

render :text => proc { |response, output|
   AWS::S3::S3Object.stream(path, bucket) do |segment|
     output.write segment
     output.flush # not sure if this is needed
   end
 }

Depending on your webserver this may (mongrel) or may not (webrick) work, so don't get too frustrated if it doesn't stream in development.

like image 38
Justin Avatar answered Nov 14 '22 23:11

Justin