3

I'm looking for a way to protect images uploaded from a Heroku Rails 3 app using the dragonfly gem to a S3 storage. I'd like to control access on a user basis and ensure that the images can't be accessed directly.

I've found some information for other gems such as paperclip, but since dragonfly works a bit differently, I'm not sure what's the preferred way to deal with this case.

polarblau
  • 17,649
  • 7
  • 63
  • 84

3 Answers3

2

Dragonfly allows an :expires option for remote_url that is a wrapper for url_for of S3DataStore. See here. What about setting a restricted download link tha expires in 10 seconds as they do with paperclip?

You can also add random guid for your images inside their URL to provide more security as per this SO question.

Not a real solution, just some thoughts.

Community
  • 1
  • 1
microspino
  • 7,693
  • 3
  • 48
  • 49
2

Since I’m currently using a routed endpoint, expiring urls unfortunately don’t work for me.

I found, that setting an x-amz-acl header to set the permissions, works in my case since all images are exclusively accessed through the application and never directly.

# config/initializers/dragonfly.rb
app = Dragonfly[:images]

if Rails.env.production?
  app.datastore.configure do |c|
    # […]
    c.storage_headers = {'x-amz-acl' => 'private'}
  end
end

Another way to do this programmatically for some images can be achieved using calling the method put_object_acl directly on the Dragonfly’s Fog storage instance, e.g. in a model callback:

app = Dragonfly[:images]
app.datastore.storage.put_object_acl 'bucket-name', model.image_uid, 'private'

This will of course work only if the storage in use is in fact a Fog storage, hence a check would be needed.

I don’t have any tests for this solution currently, since it seems to involve a lot of mocking. So, if anyone has some input on this solution, I would highly appreciate hearing about it!

polarblau
  • 17,649
  • 7
  • 63
  • 84
  • Hi polarblau - How are you accessing this information via your application? Is your application a web-page? If so, what syntax is needed to render the images? – Tabrez Apr 12 '12 at 06:52
  • As mentioned, I’m using Dragonfly (a Ruby gem), in this case with Rails. Here are the docs: http://markevans.github.com/dragonfly/file.GeneralUsage.html – polarblau Apr 12 '12 at 09:55
  • Hi Polarblau - I was asking the question in context of Dragonfly itself. You shared the code for ensuring that the images on S3 are marked as private. How do you access those images from the end-user's browser after storing them as "private"? Are you using server side code to fetch the images and then write them out on the http response, or are you using something more convenient? It will be great if you can share that piece of information. I have scanned the dragonfly documentation and I do not see anything like that. – Tabrez Apr 13 '12 at 13:36
  • I see. Well, I'm just using standard dragonfly methods (e.g. `@model.image.url` for full size or `@model.image.thumb('250x250>')` for a thumbnail). Since with dragonfly all requests to images go through the server anyways, everything seems to function as before. Does this help you? – polarblau Apr 13 '12 at 18:12
1

You can use Amazon S3's expiring URLs. This is a signed URL that has an expiry time. Therefore you generate the URL, give it to the user, and it's up to them to read that file within the allotted time. For instance, if you're loading images within a page that need to be secure, set the expiry to 10 seconds or so.

Files must be stored as NOT world readable obviously.

From looking at Dragonfly this appears to be quite simple:

my_model.attachment.remote_url(:expires => 10.seconds.from_now)

More info here: http://markevans.github.com/dragonfly/file.DataStorage.html#S3_datastore

If that doesn't work, I know that Paperclip supports this behaviour as I've used it several times in the past.

Neil Middleton
  • 22,105
  • 18
  • 80
  • 134
  • Thanks, sounds interesting. I'm also fetching images directly through a routed endpoint, which is a feature dragonfly provides. I'll have to see if I can make this work as well. – polarblau Jan 17 '12 at 06:47