原文地址:http://guides.rubyonrails.org/security.html
這個指南描述的是在web應用裡普遍的安全問題,同時也給出了在Rails裡如何避免這些問題。如果你有任何問題,請mail作者,Heiko Webers, at 42 {et} rorsecurity.info. 讀完此文後,你應該會了解:
1.所有的對策已經被高亮顯示了
2.在Rails裡session的概念, 該放什麼在session裡,以及一些流行的攻擊方法
3.只是浏覽一個站點,怎麼就有安全問題呢?(with CSRF)
4.當你使用files或提供一個管理界面的時候需要注意些什麼
5.The Rails-specific mass assignment problem
6.如何管理用戶:登陸,注銷以及對所有層面的攻擊方法。
7.以及最流行的注入攻擊方法。
一 介紹
web application框架幫助開發者建立種種web應用,某些框架在安全方面也幫你省心不少。事實上,一個框架並不比另一個安全。對於大多 數的框架來說,如果你正確使用它,可以建立安全的應用。Ruby on Rails有許多聰明的helper方法,例如防止注入攻擊的方法,這讓sql注入 變成了困難的事情。很高興看到我審定的所有rails app都有一個良好的安全級別。
一般沒有這種即插即用的安全,安全依賴於正在使用的框架,有時候也依賴於開發方式。它取決於web應用的所有環境:後端存儲,網絡服 務器和網絡應用程序本身(以及可能的其他層或應用程序) 。
Gartner組織估計大約75%的攻擊都是在web應用,並且在300個調查的web應用裡,97%都是容易被攻擊的。這是因為web應用容易攻擊,因為 它們易於理解和操作,甚至是懶人。
在受到威脅的web應用中,包括用戶帳戶劫持,繞開訪問控制,閱讀或修改敏感數據,或出示虛假的內容。或攻擊者可以安裝一個特洛伊木 馬程序或不請自來的電子郵件發送軟件,目的是在金融活動或造成損害品牌名稱,修改公司的資源。為了防止攻擊,最大限度地減少其影響和 消除攻擊點,首先,你必須充分了解攻擊方法,以便找到正確的對策。這正是該指南的目的。
為了開發安全的Web應用你必須不斷更新的所有層次和了解你的敵人。要不斷更新訂閱的安全郵件列表,請閱讀安全博客,並更新和安全檢 查的習慣。我手工做這些,因為這你才能找到討厭的合乎邏輯的安全問題。
二 Sessions
我們的安全之旅最好是從最易受到特別攻擊的sessions開始。
2.1 什麼是sessions
— HTTP is a stateless protocol Sessions make it stateful.
- HTTP是一個無狀態協議,Sessions使它有狀態。
大多數的應用需要對一個特別用戶的某些狀態進行跟蹤。比如,一個購物車的內容,一的當前登陸用戶的id,如果沒有sessions這個好主意 ,用戶必須在每一個請求都得去標識驗證身份。如果一個新用戶訪問這個應用,Rails會自動創建一個新的session。如果用戶之前使用過這個 應用,它會自動加載一個存在的session。
一個session通常是一個hash和一個session id(通常是一個32個字符的字符串)來標識這個hash。Rails裡你可以用如下方式保存和使用 session:
session[:user_id] = @current_user.id
User.find(session[:user_id])
2.2 session id
— The session id is a 32 byte long MD5 hash value.
- session id就是個一32位的md5 hash值。
一個session id由一個隨機字符串的hash值組成。這個隨機字符串是當前的時間,一個0和1之間的隨機數字,一個ruby解釋器進程id數字和 一個常量字符串組成。
2.3 session劫持
- 竊取用戶session id的攻擊者可以在一個web應用裡使用受害者的名字。
許多web應用都有一個驗證系統:一個用戶提供一個用戶名和密碼,web應用檢查並且存儲相應的user id到session的這個hash裡。從現在開 始,session是有效的。在每個http請求裡, 應用會加載這些在session裡用user id來標識的用戶,並不需要新的驗證。這個session id是放 在cookie裡用來標識這個session的。
因此cookie作為web應用的臨時驗證。任何人得到一個別人的cookie,他就可以偽裝為這個人使用對應的web應用-可能會有嚴重的後果。這 裡有一些session劫持的方法,以及對策:
1.在不安全的網絡進行嗅探cookie。無線局域網就是這樣一個例子。在這樣的一個網絡裡,特別容易去監聽所有鏈接的客戶端, 這就是不 去咖啡店工作的原因(某些sb就喜歡去星巴克打開本本裝比)。對於web應用開發者,這就意味著去提供一個安全的ssl連接。
2.大多數的人在公共場所工作之後不清除cookie,所以如果是最後一個沒有在web應用注銷的用戶,你有可能偽裝成這個用戶。在web應用裡 提供給用戶一個注銷按鈕,並且放在醒目的位置。
3.許多跨站點腳本( XSS )攻擊的目的是獲得用戶的cookie 。你之後會看到關於xss的更多內容。
4.Session定制,之後會讀到.
大多數攻擊者的目的是為了錢,失竊的銀行登陸帳號的價格范圍從$10 - $1000不等(取決於可用的資金數額),信用卡號碼是$0.40-$20, 在線拍賣網站的帳號為$1-$8,email密碼為$4-$30 ,參考賽門鐵克的網絡安全威脅報告。
2.4 session 准則
-這裡有一些session的一般准則
1.不要在session裡存儲大的對象。相反,你應該把它們存儲在數據庫裡,把它們的id保存在session裡。這將消除同步的麻煩,而且也不會 占用你session的存儲空間(取決於你選擇的session的存儲)
2.關鍵的數據不應該被存儲在session裡。如果用戶清除了cookie或者關閉了浏覽器,它們都將丟失,用一個客戶端session存儲,用戶可以 讀取數據。
2.5 session存儲
- Rails為session提供了很多存儲機制,最重要的是ActiveRecordStore和CookieStore。
大多數實際生活的應用選擇ActiveRecordStore (或其衍生物)的文件存儲由於性能和維修的原因。 ActiveRecordStore保持session ID和 散列在一個數據庫表,在每次請求裡都保存和檢索這個hash。
Rails2介紹了一種新的session存儲機制, CookieStore. 它直接在客戶端的cookie裡保存這個session hash。服務端從cookie裡檢索這個 session hash,無須session id。這將大大增加速度的應用,但它是一個有爭議的存儲選項,你必須思考安全的影響:
1.cookie意味著嚴格的大小限制,4k。 這點是好的,本身就不應該存儲大的數據在session裡,前面也說過。存儲一個當前用戶的數據庫id 一般是沒有問題的。
2.客戶端能看到你存儲在session裡的一切。因為是明文的(實際是base64編碼的),所以,你別想在這裡存儲任何秘密。為了防止session hash被篡改,會從服務端加一個secret到cookie的末尾。
這就意味著,這個安全存儲取決於這個scret(digest算法,默認是sha512,至今沒有被破解),所以不要用一個簡單的scret,例如字典裡 的一個單詞,或者比30個字符短的任意字符串。把這個scret放在environment.rb裡:
config.action_controller.session = {
:session_key => ‘_app_session’,
:secret => ‘0x0dkfj3927dkc7djdh36rkckdfzsg...’
}
但是也有經過加密session hash的CookieStore派生存儲機制,為了客戶端不能看到它。
2.6 針對於CookieStore sessions的重放攻擊
- 另一種必須要知道的攻擊是針對於cookiestore攻擊是重放攻擊。
它的運作方式如下:
1.用戶收到貸款,金額是儲存在一個session裡,(這是壞主意,但是我們做這些只是示范)
2.這個用戶買了一些東西
3.他的new,lower credit將要被存儲在session裡。
4.邪惡的用戶得到了他的cookie並且覆蓋了當前的cookie。
5.這個用戶有了他的credit, 就可以進行重放攻擊了。
在session裡加一個(nonce)暫時標志(隨機值)可以解決重放攻擊這個問題。一個nonce僅有效一次,並且服務端保持對所有有效nonce的 跟蹤,如果你有多個應用服務器,它可能甚至會更復雜,避免把nonce存儲在數據庫裡,這樣會破壞整個CookieStore。
最好的解決方法是不要存放這種數據在session裡,而是在數據庫裡。這個例子,存儲credit在數據庫裡,logged in user id 放在session 裡。
2.7 session 定制攻擊
- 除了竊取用戶的session id,攻擊者還可能去定制一個session id來偽裝,這就是所謂的session定制。
這個攻擊的重點是定制一個用戶的可以識別他的session id,並且強制用戶的浏覽器用這個id。因此後來攻擊者也不需要去竊取一個 session id了。來看看攻擊是如何展開的:
1.攻擊者創建一個有效的session id: 他登陸想定制session的那個web應用的登陸頁面,這時就通過response在cookie裡有一個session id了(圖中的1,2)
2.他可能保持這次會話(session)。session是會過期的,比如每隔20分鐘,這會大大的減少了攻擊者的時間。因此,他會不斷的訪問這個 web應用以便於保持session可用。
3.現在,攻擊者會強迫用戶來使用這個session id(看圖裡的3),因為你不能改變另一個域的cookie,攻擊者不得不在目標web應用裡運行 一個javascript腳本。通過往目標web應用注入javascript代碼來完成這次攻擊。下面是一個例子:
<script>
document.cookie="_session_id=16d5b78abb28e3d6206b60f22a03c8d9";
</script>
4. 攻擊者引誘受害人向被感染的網頁上的JavaScript代碼。通過查看網頁時,受害者的浏覽器將把session id改變成攻擊者定制好的 session id。
5.因為這個陷進session id沒有被用,web應用會需要用戶去驗證。
6.從現在開始,受害者和攻擊者都會共有一個相同的session在這個web應用裡。此時受害者並沒有注意到這次攻擊。
2.8 session 定制 --- 對策
- 一行代碼就保護你不被session定制侵害。
(我的這篇文章也寫了一些對策:http://blackanger.blog.51cto.com/140924/91764)
最有效的對策就是在成功登陸以後,創建一個新的session id,並且宣告舊的session id失效。那樣,攻擊者就不能用固定的session id了 。這是一個對方session劫持的好的對策。Rails裡我們可以這樣來產生一個新的session:
reset_session
如果你用流行的rails插件,RestfulAuthentication,請在SessionsController#create action裡加 reset_session. 注意,這個行為消 除了原session裡存儲的所有值,你必須把這些值得轉移到新的session裡。
另一個有效的對策是,在session裡保存用戶的特定屬性,在每次請求進來的時候驗證他們,如果信息不匹配,則拒絕訪問。可以用遠程ip 地址,或者是訪問浏覽器名稱,盡管後者是不常用的。當保持ip的時候要注意,應該保持用戶真實ip,而不是互聯網服務供應商或大型組織的ip ,如果這些變化以後,某些用戶可能無法使用這個web應用,或者會有限制。
2.9 session 過期
- 永不過期的session會更加方便這些session攻擊。
session過期時間在服務端設置更加安全。下面是一個例子, 如何在數據庫裡設置session的過期時間。如果超過20分鐘就調用 Session.swap(20m):
class Session < ActiveRecord::Base
def self.sweep(time_ago = nil)
time = case time_ago
when /^(\d+)m$/ then Time.now - $1.to_i.minute
when /^(\d+)h$/ then Time.now - $1.to_i.hour
when /^(\d+)d$/ then Time.now - $1.to_i.day
else Time.now - 1.hour
end
self.delete_all "updated_at < '#{time.to_s(:db)}'"
end
end
這節講述了session定制需要保持連接。雖然你有過期時間,但攻擊者也不傻, 他會保持每隔五分鐘使session可用,不過期。一個簡單的 解決方法是,增加一個created_at到你的session表裡。現在你可以刪除被創建了很久的那些session,用下面的這行替換上面swap方法的:
self.delete_all "updated_at < '#{time.to_s(:db)}' OR created_at < '#{2.days.ago.to_s(:db)}'"