如何安全下载文件

时间:2015-01-03 14:49:50

标签: ruby-on-rails ruby file

以下方法用于根据用户参数/选择下载YAML文件。

这肯定不安全,因为我可以下载层次结构中的其他YAML文件。

def download

    language_code = params[:code]
    send_file(
        "#{Rails.root}/config/locales/#{language_code}.yml",
        filename: "#{language_code}.yml",
        type: "application/yml"
    )

end

我无法控制params[:code],这本身就是动态的。

如何保护易受攻击的download方法?

1 个答案:

答案 0 :(得分:1)

您的#1选项,因为评论暗示完全禁止用户与之交互 language_code字符串。评论中有许多建议的选项:受限制 列表,数据库实现等

另一个选项(尽管你的约束可能无效)是进行长度检查:language_code.length <= 4。这假定您的语言代码不超过wikipedia's list of language codes的4个字符。

作为最后的手段,您还可以清理用户输入并清理它,以便文件路径不能 操纵。 I've written a post about file sanitization functions here。您有两种选择:

  • 白名单,只接受一小部分字符:A-Z, a-z, 0-9
  • 黑名单并消除危险字符:/ \ ? % * : | " < > . (and space)

在你的情况下(我假设你完全控制了config/locals)我会列入白名单。白名单功能是 易于创建:

def sanitize(file_name)
  # Remove any character that aren't 0-9, A-Z, or a-z
  filename.gsub(/[^0-9A-Z]/i, '_')
end

不知道您的语言文件是如何实现的,您可能需要使用下划线以外的字符_ 替换。

为了提供额外的预防措施,您还可以预先检查目录以查看该文件是否存在,从而阻止了该目录 路径遍历攻击。像这样:

def valid_path?(filename)
  Dir["#{Rails.root}/config/locales/*"].include?("#{Rails.root}/config/locales/#{filename}")
end

此处的好处是您明确声明该文件必须存在于config/locales目录中 在你服务之前。如果攻击者尝试进行目录遍历攻击,则此函数将返回false。