ruby-on-railsruby-on-rails-6rails-activestoragerails-security

Safely filter Active Storage file names?


The Securing Rails Applications rails guide (file uploads section) gives 4 great paragraphs on the dangers of blindly accepting files from users. Some highlights:

If you store file uploads at /var/www/uploads, and the user enters a file name like "../../../etc/passwd", it may overwrite an important file.

It is best to use a permitted list approach, which checks for the validity of a file name with a set of accepted characters. This is opposed to a restricted list approach which attempts to remove not allowed characters.

Suppose the developer has set up Active Storage in a minimal way to work with their application, how would they go about ensuring file names are correctly escaped/sanitized/rejected (open to recommendation on best policy here)

What I know so far

The rails guide shows this code, but gives it only as an example, without much commentary around whether it's best practice or not

def sanitize_filename(filename)
  filename.strip.tap do |name|
    # NOTE: File.basename doesn't work right with Windows paths on Unix
    # get only the filename, not the whole path
    name.sub! /\A.*(\\|\/)/, ''
    # Finally, replace all non alphanumeric, underscore
    # or periods with underscore
    name.gsub! /[^\w\.\-]/, '_'
  end
end

Is that code sufficient to protect against known file name exploits? Or is there a better way?

Example usage

I don't know exactly how to use the above method.

Suppose we have the following form to submit an image:

<%= f.label "Select one or more images" %>
<%= f.file_field :teacher_images, multiple: true %>

I am not sure exactly how sanitize_filename fits in to this


Solution

  • Its safe to say that it can be expected to be safe against that particular exploit which relies on .. being used to save the file in another directory. However there is no exclusive list of known exploits and it might not protect against potential vulnerabilities which can be specific to whatever backend is actually storing the file.

    Like for example a malicious user could overwrite other users uploads if the are all stored in the same directory.

    The only way to actually be 100% safe against known and future exploits is to not accept file names from the user and generate them on the server which is done by ActiveStorage.