這樣情況下,因為example.orge的服務器通過PHPSESSID來辨認對應的用戶的,所以服務器錯把攻擊者當成了合法的用戶。
整個過程的描述,請看下面的示例圖:
當然這種攻擊的方式,前提條件是攻擊者必須通過某種手段固定,劫持或者猜測出某個合法用戶的PHPSESSID。雖然這看起來難度很高,但是也不是不可能的事情。
安全性的加強
有很多技術可以用來加強Session的安全性,主要思想就是要使驗證的過程對于合法用戶來說,越簡單越好,然后對于攻擊者來說,步驟要越復雜越好。當然,這似乎是比較難于平衡的,要根據你應用程序的具體設計來做決策。
沒有時間寫下去,待續。。。
最簡單的居于HTTP/1.1請求包括請求行以及一些Host的頭部:
GET / HTTP/1.1
Host: example.org
如果客戶端通過PHPSESSID傳遞相關的session標識符,可以將PHPSESSID放在cookie頭部中進行傳遞:
GET / HTTP/1.1
Host: example.org
Cookie: PHPSESSID=12345
同樣地,客戶端也可以將session標識符放在請求的url中進行傳遞。
GET /?PHPSESSID=12345
HTTP/1.1Host: example.org
當然,session標識符也可以包含在POST數據中,但是這對用戶體驗有影響,所以這種方式很少采用。
因為來自TCP/IP信息也不一定可以完全信任的,所以,對于web開發者來說,利用TCP/IP中的信息來加強安全性也是不太合適的。 不過,攻擊者也必須提供一個合法用戶的唯一的標識符,才能假扮成合法用戶進入系統。因此,看起來唯一能夠有效的保護系統的措施,就是盡量地隱藏 session標識符或者使之難于猜測出來。最好就是兩者都能實施。
PHP會自動生成一個隨機的session ID,基本來說是不可能被猜測出來的,所以這方面的安全還是有一定保障的。但是,要防止攻擊者獲取一個合法的session ID是相當困難的,這基本上不是開發者所能控制的。
事實上,許多情況下都有可能導致session ID的泄露。 比如說,如果通過GET數據來傳遞session ID的話,就有可能暴露這個敏感的身份信息。因為,有的用戶可能會將帶有session ID的鏈接緩存,收藏或者發送在郵件內容中。Cookies是一種像相對來說安全一點的機制,但是用戶是可以在客戶端中禁止掉cookies的!在一些 IE的版本中也有比較嚴重的安全漏洞,比較有名的就是會泄露cookies給一些有安全隱患的邪惡站點。
因此,作為一個開發者,可以肯定session ID是不能被猜測出來的,但是還是有可能被攻擊者使用某些方法獲取到。所以,必須采取一些額外的安全措施來防止此類情況在你的應用程序中發生。
實際上,一個標準的HTTP請求中除了Host等必須包含的頭部,還包含了一些可選的頭部.舉一個例子,看下面的一個請求:
GET / HTTP/1.1
Host: example.org
Cookie: PHPSESSID=12345
User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; en-US; rv:1.8.1.1) Gecko/20061204 Firefox/2.0.0.1
Accept: text/html;q=0.9, */*;q=0.1
Accept-Charset: ISO-8859-1, utf-8;q=0.66, *;q=0.66
Accept-Language: en
我們可以看到,在以上的一個請求例子中包含了四個額外的頭部,分別是User-Agent, Accept, Accept-Charset以及Accept-Language。因為這些頭部不是必須的,所以完全依賴他們在你的應用程序中發揮作用是不太明智的。但是,如果一個用戶的瀏覽器確實發送了這些頭部到服務器,那么可以肯定的是在接下來的同一個用戶通過同一個瀏覽器發送的請求中,必然也會攜帶這些頭部。當然,這其中也會有極少數的特殊情況發生。假如以上例子是由一個當前的跟服務器建立了會話的用戶發出的請求,考慮下面的一個請求:
GET / HTTP/1.1
Host: example.org
Cookie: PHPSESSID=12345
User-Agent: Mozilla/5.0 (compatible; IE 6.0 Microsoft Windows XP)
因為有相同的session id包含在請求的Cookie頭部中,所以相同的php session將會被訪問到。但是,請求里的User-Agent頭部跟先前的請求中的信息是不同的,系統是否可以假定這兩個請求是同一個用戶發出的?
像這種情況下,發現瀏覽器的頭部改變了,但是不能肯定這是否是一次來自攻擊者的請求的話,比較好的措施就是彈出一個要求輸入密碼的輸入框讓用戶輸入,這樣的話,對用戶體驗的影響不會很大,又能很有效地防止攻擊。
當然,你可以在系統中加入核查User-Agent頭部的代碼,類似Listing 3中的代碼:
Listing 3:
session_start();
if (md5($_SERVER['HTTP_USER_AGENT']) != $_SESSION['HTTP_USER_AGENT'])
{ /* 彈出密碼輸入框 */ exit;
}
/* Rest of Code */ ?>
當然,你先必須在第一次請求時,初始化session的時候,用MD5算法加密user agent信息并且保存在session中,類似下面listing4中的代碼:
Listing 4:
session_start();
$_SESSION['HTTP_USER_AGENT'] = md5($_SERVER['HTTP_USER_AGENT']);
?>
雖然不一定需要用MD5來加密這個User-Agent信息,但使用這種方式以后就不需要再過濾這個$_SERVER['HTTP_USER_AGENT']數據了。不然的話,在使用這個數據以前必須要進行數據過濾,因為任何來自客戶端的數據都是不可信任的,必須要注意這一點。
在你檢查這個User-Agent客戶端頭部信息以后,做為一個攻擊者必須要完成兩步才能劫持一個session:
獲取一個合法的session id
包含一個相同的User-Agent頭部在偽造的請求中
原文轉自:http://www.anti-gravitydesign.com