程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> Rails開發細節(八)Rails應用的安全

Rails開發細節(八)Rails應用的安全

編輯:關於JAVA

看過本文之後,你應該熟悉下面的內容:

所有顯著的對策。

rails中session的概念,其中存放的內容,常見的攻擊手段。

rails中大量的分配問題。

在提供管理接口的時候,你不得不關注的一些事情。

如何管理用戶:登陸,退出,在各個層面的攻擊方法。

常見的注入攻擊方法。

1.簡介

web框架幫助開發者構建web應用。它們中的一些還可以幫助你構建安全的web應用。事實上一個框架並不比兩一個框架安全,如果你正確的使用,你可以用很多框架構建安全的web應用。rails包含一些聰明的幫助工具,例如防止注入攻擊的工具,因此這幾乎不是什麼問題。高興的是,我審計過的很多rails應用都有一個很好的安全級別。

通常來說,沒有即插即用的安全。安全依賴於使用框架的人,有時候是開發的方法。它依賴於web應用環境的所有層:後端存儲,web服務器,web應用本身(甚至可能是其它層或者其他應用)。

Gartner Group估計大約75%的攻擊發生在web應用層,發現在審計的300個站點中,97%是容易受到攻擊的。這是因為相對來說,web應用更容易攻擊,因為它們容易理解和操作,設置非專業人士都可以理解和操作。

web應用的威脅包括用戶賬戶劫持,繞開訪問控制,讀寫敏感數據,顯示欺騙信息。甚至一個攻擊者還可能會安裝木馬程序,或者是一個主動的電子郵件發送軟件,目標是金融數據,或者是通過修改公司的資源來破壞品牌。為了阻止攻擊,最小化攻擊的影響,移除攻擊點,首先要做的是,你需要完全理解攻擊的方法,才可以找到正確的對策。這就是本文的目的。

為了開發安全的web應用,你不得不保持各層的更新,並且了解你的敵人。訂閱安全郵件列表,保持最新的信息,閱讀安全類的博客。我是通過手動完成的,因為那就是你如何發現下流的邏輯安全問題。

2.sessions

開始了解安全的一個好地方就是session,很容易受到特殊攻擊的地方。

2.1.什麼是session

http是一個無狀態的協議,session使得它有了狀態。

大多數應用需要跟蹤特定用戶的狀態。這可能是購物車中的內容,或者是一個登陸用戶的userid。如果沒有session,用戶需要在每次請求進行識別和驗證。在新用戶訪問應用的時候,rails會自定創建新的session。如果用戶已經使用了應用,會加載一個已經存在的session。

session由一個哈希值和一個sessionid組成,sessionid通常是一個32個字符的哈希字符串。每個發送到客戶端浏覽器的cookie都包含sessionid。浏覽器在客戶端的每個請求中會將sessionid發送回來。在rails中你可以通過下面的代碼保存和獲取session值。

session[:user_id] = @current_user.id 
User.find(session[:user_id])

2.2.session id

sessionid是一個32字節的md5哈希值。

sessionid由隨機字符串的哈希值組成。隨機字符串包括當前時間,0-1之間的隨機數,ruby解釋器的進程id(也是一個隨機數字),一個常量字符串。當目前為止,暴利攻擊rails的sessionid是不可行的。MD5是不可逆的,但是可以碰撞,因此創建一個相同哈希值的字符串只是存在理論的可能性。

2.3session劫持

偷了一個用戶的sessionid之後,一個攻擊者就可以用受害者的名義訪問web應用。

很多web應用都有驗證系統:用戶提供登陸賬號和登錄密碼,web應用驗證這些信息,驗證通過之後,將用戶的id保存到session中。在這之後,這個session就是有效的了。每次請求都會加載用戶,通過session中的用戶id識別用戶,不需要再次驗證。在cookie的sessionid用來識別session。

因此,cookie為web應用提供了臨時的驗證功能。每個從某個人哪裡獲取cookie的用戶,可以以那個人的名義使用web應用,可能會產生嚴重的後果。下面是一些劫持session的方法,已經相應的對策。

在不安全的網絡中嗅探cookie。無線局域網就是這樣一個網絡環境。在一個非加密的無線局域網,尤其容易監聽所有連接客戶端的通信。這就是為什麼不要再咖啡店工作的原因。web應用的構建者應該通過SSL來提供一個安全的連接。在Rails3.1以及後續版本,可以在配置文件中進行配置,來強迫在應用中使用SSL連接。

config.force_ssl = true

大多數的人在公共終端工作之後,沒有清除cookie。如果剛才的用戶沒有退出web應用,你就可以以剛才那個用戶的身份使用web應用。在web應用中給用戶提供一個log-out按鈕,並且放在顯著的位置。

很多跨站點攻擊腳本cross-site scripting(XSS)的目標就是獲取用戶的cookie。

不是偷一個對攻擊者來說未知的cookie,而是將用戶的session的身份(在cookie中)修改為他可以認識的。在後面會講到這個所謂的session固定。

大多數攻擊者的主要目的是獲取金錢。偷一個銀行賬號的私下價格是10-1000美元,獲取信用卡號是0.4-20美元,拍賣網站的賬戶是1-8美元,電子郵件密碼是4-30美元。

2.4.session指南

下面是一些常用的session指南

不要再session中存儲大對象。將內容存儲到數據庫,在session中只保存數據的id。這可以消除同步這個令人頭痛的問題,還不會占滿session的存儲空間(這依賴於你選擇存儲session的類型)。服務端的session存儲空間你可以清除session,但是很難減輕客戶端的存儲空間壓力。

關鍵的數據不應該存儲在session中。如果用戶清除了他的cookie,或者是關閉了浏覽器,這些信息就會消失。在客戶端的session存儲,用戶可以讀取數據。

2.5.session存儲

rails提供了若干session存儲機制。最重要是ActiveRecord::SessionStore和ActionDispath::Session::CookieStore。

有很多的session存儲,rails存儲session的哈希值和sessionid。大多數實時應用選擇ActiveRecord::SessinStore(或者是它的派生類),通過文件存儲,由於性能和維護的原因。ActiveRecord::SessionStore將哈希值和session id存儲在數據庫表中,在每次請求都會保存和獲取哈希值。

Rails2引入了一種新的默認session存儲方式,CookieStore。將session哈希值直接存儲在客戶端的cookie中。服務端直接從cookie中獲取session哈希值,消除了對於session id的需要。極大地增加了應用的速度,但是這是個有爭議的存儲方式,你不得不考慮隱藏的安全問題:

cookie的大小嚴格限制為4KB。這還好,之前講過,你不應該在session中存儲大數據。在session存儲當前用戶的數據庫id通常是可以的。

客戶端可以看到在session中存儲的所有內容,因為是明文存儲(事實上是base64編碼,但是沒有加密)。當然,你不會在裡面存儲任何秘密。為了防止session哈希值被篡改,從session中用服務端的密鑰計算的一個數字會被插入到cookie的最後面。

這就意味著這種儲存方式依賴於這個密鑰(和這個數字算法,默認是SHA512,還沒有被破解)。因此不使用不重要的密鑰,例如字典中的一個單詞,或者是短於30個字符。把這個密鑰放在你的environment.rb中。

config.action_dispatch.session = { 
  :key    => '_app_session', 
  :secret => '0x0dkfj3927dkc7djdh36rkckdfzsg...'
}

因為CookieStore的繼承類加密session哈希值,因此客戶端是看不到的。

2.6.重復CookieStore session的攻擊

你需要注意的另一種攻擊是,在使用CookieStore的時候,受到的重復攻擊。

攻擊的過程是這樣的:

一個用戶收到信用卡信息,金額存儲在session中(這不是一個好主意,我們只是來證明)。

這個用戶買了一些東西。

2.7.固定session

1.首先,攻擊者會訪問目標網站。訪問之後會產生一個session,這個session是合法的。

2.攻擊者想辦法讓目標用戶使用這個合法的session。使用下面的代碼就可以修改頁面的session。

<script> document.cookie="_session_id=16d5b78abb28e3d6206b60f22a03c8d9"; </script>

3.攻擊者引誘目標用戶訪問受過污染的頁面,訪問受污染的頁面之後,目標用戶就開始使用前面的合法的session。

4.目標用戶使用攻擊者的session在目標網站登錄驗證。

5.攻擊者和目標用戶共享一個session,攻擊者就可以獲取用戶信息等其他信息。目標用戶完全不知情。

2.8.固定session的對策

最有效的辦法就是在登錄之後,聲明舊的session失效。這樣,攻擊者就不能使用自己的哪個session或者目標用戶的信息了,因為登錄之後,重新分配了session。

還有一個辦法,就是記錄每次請求的其他信息,例如ip,浏覽器類型等,每次請求都去驗證當前請求和上次請求的這些信息是否匹配,來決定是否拒絕提供服務。

2.9.session過期

不僅在cookies中聲明session的過期時間,而且在服務端也同時檢查session是否過期。

3.CSRF跨站請求偽造

1.受害者浏覽一篇博客,博客是攻擊者准備好的,博客中有一張圖片,圖片的地址是

<img src="http://www.webapp.com/project/1/destroy">

2.我們知道,一張圖片會產生一個請求,請求的地址就是img的src的內容。

3.受害者在webapp.com上的session還沒有過期,因為他剛才還在浏覽webapp.com,而且還沒有退出。

4.受害者的浏覽器發出請求http://www.webapp.com/project/1/destroy,刪除id為1的project。

5.webapp.com驗證受害者的session合法,然後執行這個請求,這個project被刪除。請求的結果對於img來說是非預期結果,所以不會在網頁上有任何顯示。

6.受害者沒有意識到任何事情,但是他再webapp.com上的project已經被刪除了。

3.1.CSRF對策

首先,要正確使用get和post。

其次,在非get請求中增加token驗證來保護你的應用免受csrf攻擊。

post請求可以用代碼發出。

下面就是一個例子。

<a href="http://www.harmless.com/" onclick=" 
  var f = document.createElement('form'); 
  f.style.display = 'none'; 
  this.parentNode.appendChild(f); 
  f.method = 'POST'; 
  f.action = 'http://www.example.com/account/destroy'; 
  f.submit(); 
  return false;">To the harmless survey</a>

在a標簽中內嵌了一個form,發送post請求,對數據造成破壞。

攻擊代碼也可以放在img的mouse事件中。

<img src="http://www.harmless.com/img" width="400" height="400" onmouseover="..." />

一個應對csrf的辦法就是在非get請求中加入token驗證,在rails中已經內置了這種方法,只需要在applicationcontroller中加入下面一行代碼。默認是已經加好的。

protect_from_forgery :secret => "123456789012345678901234567890..."

4.跳轉和文件

在web應用中,還有一些安全漏洞是與跳轉和文件相關的。

4.1.跳轉

任何使用使用url傳遞的參數引導用戶進行跳轉,都可能是一個漏洞。

大部分的攻擊都是把受害者引入一個假冒的網站,看起來和剛才的網站很相似。這就是所謂的釣魚攻擊

對付這類攻擊的簡單辦法就是為跳轉參數設立白名單,然後檢查參數值是否在白名單中,再決定是否跳轉。

4.2.文件上傳

很多應用都允許用戶上傳文件,用戶可以自由設置文件的名稱,這樣攻擊就可能會使用惡意的文件替代服務器中的文件。你允許用戶上傳文件到/var/www/uploads,可是用戶寫了一個文件名../../../etc/passwd,這樣就覆蓋了系統的passwd文件,很可怕的。當然了,ruby解釋器需要設置適當權限,還有就是很多服務的訪問者也需要設置適當的權限。

在進行文件名檢查的時候,不用刪除惡意的部分。較好的做法是設立白名單,然後檢查文件名是否符合白名單設置,是否為可接受的字符。或者設計黑名單,將非法字符進行替換。遇到文件名包含非法字符的時候,要麼拒絕,要麼進行替換,不用刪除。

用同步處理文件上傳的過程,一個重大的漏洞就是拒絕服務攻擊。攻擊者可以同時上傳多個文件,然後服務器就可能會由於超過負載而崩潰。

最好是異步處理文件。先保存文件,然後在另外一個線程處理文件。

4.3.上傳文件中的可執行代碼

如果上傳的文件中包含可執行代碼,會很危險。再上傳的時候,應該對上傳的文件類型進行檢查,不僅是後綴的檢查,而且也要檢查文件的真實類型。

如果webserver使用的是apache,不要將上傳的文件放在DocumentRoot目錄,這個目錄中的文件,如果是代碼文件,是可執行的。單獨放在其他目錄。

4.4.文件下載

不能隨意下載任何目錄的文件。

如果你的下載函數接受一個用戶輸入的參數,而且又不檢查的話,用戶就會下載一些重要的文件。

send_file('/var/www/uploads/' + params[:filename])

“../../../etc/passwd”

一個好的做法就是將文件的目錄存放在數據庫中,還有id,然後根據這個目錄下載文件。

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved