2015-01-03 53 views
2

以下方法用于根据用户参数/选择下载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方法,这是脆弱的?

+0

什么是你想要防范的实例? – Anthony

+2

@Anony'database.yml'文件可以被拉。 – Nithin

+2

你可以制作一个'safe_list'或一个'unsafe_list'数组,持有language_code,你可以下载用户吗? – Anthony

回答

1

您的#1选项,正如注释所隐含的,是完全不允许用户与 字符串进行交互。在评论中有许多建议的选项:受限制的 列表,数据库实现等。

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

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

  • 白名单,并只接受字符的一小部分:A-Z, a-z, 0-9
  • 黑名单和eliminiate危险人物:/ \ ? % * : | " < > . (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。