使用params传递给send_file来清理下载URL

时间:2014-06-03 10:49:53

标签: ruby-on-rails ruby-on-rails-3 sanitization

我在目录app/assets/downloadables/中有很多文件,我希望经过身份验证的用户能够在该目录或任何子目录中的params中按名称下载任意文件。

如何清理send_file的输入以防止用户访问服务器上的任意文件?

目前我正在考虑做这样的事情,但我不相信它是安全的:

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)

这是否可以充分防止应用程序范围内的任意文件访问,或者是否有更好的改进或不同的方法?

1 个答案:

答案 0 :(得分:0)

我在这里找到了答案:http://makandracards.com/makandra/1083-sanitize-user-generated-filenames-and-only-send-files-inside-a-given-directory

需要根据链接创建此文件:

应用/控制器/共享/ send_file_inside_trait.rb

module ApplicationController::SendFileInsideTrait
  as_trait do

  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

在控制器中使用如下:

send_file_inside File.join(Rails.root, 'app', 'assets', 'downloadables'), request.path.gsub(/^\/downloads\//,'').split('/')

魔术发生在将计算出的allowed_pa​​th + file_name路径输入expand_path的情况下,它将删除任何特殊目录浏览字符串并返回绝对路径。然后将已解析的路径与allowed_pa​​th进行比较,以确保所请求的文件位于允许的路径和/或子目录中。

请注意,此解决方案需要Modularity gem v2 https://github.com/makandra/modularity