-
Notifications
You must be signed in to change notification settings - Fork 1.7k
How To: Secure Upload
Uploading files to their default directory in the Public folder can be dangerous if you're looking to restrict who can download the file. You will need to avoid uploading files to this Public directory at all costs. Instead, you can upload the file to the root of your folder where it will be inaccessible by default. We will be creating a download
in the file controller. This way, you can use authorization (like cancan) to permit access to certain files using download.
There are two ways of getting to this result, choose which you find better, don't apply both:
Option 1. Change your document_uploader.rb
(uploader file)
def store_dir
"/PATH/RAILSAPPLICATION/uploads/#{model.id}"
end
def cache_dir
"/PATH/RAILSAPPLICATION/tmp/uploads/cache/#{model.id}"
end
Option 2. Leave your document_uploader.rb
unchanged and change the root directory of CarrierWave in the carrier wave initializer config/initializers/carrierwave.rb
:
CarrierWave.configure do |config|
# These permissions will make dir and files available only to the user running
# the servers
config.permissions = 0600
config.directory_permissions = 0700
config.storage = :file
# This avoids uploaded files from saving to public/ and so
# they will not be available for public (non-authenticated) downloading
config.root = Rails.root
end
Having chosen one of the two methods above, continue the procedure below, which serves both:
Make sure that you have write access to those locations. You can then upload your files like normal. However, when you go to recall the file, you will notice that the URL is the full path of that computer where the file is located. This just won't work! In this example, I am uploading a file to
/uploads/fileid/filename.extension
In my routes.rb
, I will need to change the path to my file.
match "/uploads/:id/:basename.:extension", :controller => "redocuments", :action => "download", :conditions => { :method => :get }
In my controller, I will need to create and pass some variables to dynamically change the link.
def download
path = "/#{redocument.redocument}"
send_file path, :x_sendfile=>true
end
In my view, I can create my URL link to the file
<%= link_to File.basename(f.redocument.url), "/uploads/#{f.id}/#{File.basename(f.redocument.url)}" %>