Neil
Neil

Reputation: 5178

Authorizing Access to Attachments (using paperclip gem)

By Default: the paperclip gem saves attachments within the public directory. As I understand it: Files within the public directory by definition are always available to users. Especially if users know the url to a certain attachment within the public directory: that attachment is not secure.

Example: Here is the default saving file structure for an image attachment when using paperclip:

default_saving_structure

So since the attachment is within the public directory: anyone can access this image if they know this url:

#image accessible to everyone when stored in the public directory
http://localhost:3000/system/users/ex_imgs/000/000/031/original/nthornepng.png?1452466215

I am very familiar with the authorization library: Pundit. However, Pundit will not be able to stop access to attachments saved in the public directory.

Question: Where/how can I save attachments so that I am able to authorize access to those attachments? If the public directory is not the place to save them: where can I save the attachments so that authentication must be successful prior to accessing the attachment?

I am familiar with this article but am still struggling with figuring this out.

Paperclip Documentation

Upvotes: 2

Views: 770

Answers (1)

Aetherus
Aetherus

Reputation: 8898

You have 2 choices:

First choice is to store the uploaded files in a non-public directory, and provide a controller action to authenticate the user and let her download the file. You can use any authentication library. As for the download part, just use the helper method send_file

the model class

class MyModel < ActiveRecord::Base
  has_attached_file :image, :path => '/non-public/dir/:attachment/:id/:style/:basename.:extension',
                            :url => '/downloads/:id'
end

the controller

class DownloadsController
  def show
    # Authenticate user
    model = MyModel.find(params[:id])
    send_file model.image.path
  end
end

The second choice is simple, keep the file in the public directory, but give it a random path which is hard to guess. And you also have to provide a controller action to authenticate users, but this time, instead of sending files to the users, you just redirect them to the file URL.

Pros and Cons

The first choice is very safe, but it requires your rails application to handle the file download. If you're using a threaded or preforked server, this could be a penalty to concurrency.

The second choice is less safer, but you can rely on your HTTP server (e.g. Nginx) to handle the file download, while rails application only do the authentication. It's much faster.

Upvotes: 2

Related Questions