2015-01-03 77 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。