Rails安全導讀【一】

Ruby On Rails  安全導讀

這個指南描述的是在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定製侵害。
(我的這篇文章也寫了一些對策:[url]http://blackanger.blog.51cto.com/140924/91764[/url]

最有效的對策就是在成功登陸以後,創建一個新的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)}'"
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章