ruby on rails - Sanitising a download URL with params being passed to send_file -
i have numerous files in directory app/assets/downloadables/
, want authenticated users able download arbitrary files name in params within directory or subdirectories.
how can sanitise input send_file
prevent users accessing arbitrary files on server?
at moment i'm looking @ doing this, i'm not confident it's safe:
downloads_root = file.join(rails.root, "app", "assets", "downloadables") # e.g. request.path = "/downloads/subdir/file1.pdf" file = request.path.gsub(/^\/downloads\//,'').gsub('..','').split('/') # send file /app/assets/downloadables/subdir/file1.pdf send_file file.join(downloads_root, file)
would sufficiently protect against app-wide arbitrary file access or there improvements or different approach better?
i found answer here: http://makandracards.com/makandra/1083-sanitize-user-generated-filenames-and-only-send-files-inside-a-given-directory
this file needed created per link:
app/controllers/shared/send_file_inside_trait.rb
module applicationcontroller::sendfileinsidetrait as_trait private def send_file_inside(allowed_path, filename, options = {}) path = file.expand_path(file.join(allowed_path, filename)) if path.match regexp.new('^' + regexp.escape(allowed_path)) send_file path, options else raise 'disallowed file requested' end end end end
to used follows in controllers:
send_file_inside file.join(rails.root, 'app', 'assets', 'downloadables'), request.path.gsub(/^\/downloads\//,'').split('/')
the magic happens calculated path of allowed_path + file_name entered expand_path
strip out special directory browsing strings , return absolute path. resolved path compared against allowed_path ensure file being requested resides within allowed path and/or sub-directories.
note solution requires modularity gem v2 https://github.com/makandra/modularity
Comments
Post a Comment