Reputation: 5178
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:
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.
Upvotes: 2
Views: 770
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.
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