最常見的針對會話的攻擊方式是會話劫持。它是所有攻擊者可以用來訪問其它人的會話的手段的總稱。所有這些手段的第一步都是取得一個合法的會話標識來偽裝成合法用戶,因此保證會話標識不會洩露非常重要。前面幾節關於會話暴露和固定的知識能幫助你保證會話標識只有伺服器及合法用戶才能知道。
深度防範原則(見第一章)可以用在會話上,當會話標識不幸被攻擊者知道的情況下,一些不起眼的安全措施也會提供一些保護。身為一個關心安全的開發者,你的目標應該是讓前述的偽裝過程變得更複雜。記住無論多小的障礙,都會以你的應用程式提供保護。
把偽裝過程變得更複雜的關鍵是加強驗證。會話標識是驗證的首要方法,同時你可以用其它資料來補充它。你可以使用的所有資料只是在每個HTTP請求中的資料:
GET / HTTP/1.1 Host: example.org User-Agent: Firefox/1.0 Accept: text/html, image/png, image/jpeg, image/gif, */* Cookie: PHPSESSID=1234
你應該意識到請求的一致性,並把不一致的行為視為可疑行為。例如,雖然User-Agent(發出本請求的瀏覽器類型)頭部是可選的,但是只要是發出該頭部的瀏覽器通常都不會變化它的值。如果你一個擁有1234的會話標識的使用者在登入後一直用Mozilla Firfox瀏覽器,突然轉換成了IE,這就比較可疑了。例如,此時你可以用要求輸入密碼方式來減輕風險,同時在誤報時,這也對合法使用者產生的衝擊也比較小。你可以用下面的程式碼來偵測User-Agent的一致性:
<?php session_start(); if (isset($_SESSION['HTTP_USER_AGENT'])) { if ($_SESSION['HTTP_USER_AGENT'] != md5($_SERVER['HTTP_USER_AGENT'])) { /* Prompt for password */ exit; } } else { $_SESSION['HTTP_USER_AGENT'] = md5($_SERVER['HTTP_USER_AGENT']); } ?>
我觀察過,在某些版本的IE瀏覽器中,使用者正常造訪一個網頁和刷新一個網頁時發出的Accept頭部資訊不同,因此Accept頭部不能用來判斷一致性。
確保User-Agent頭部資訊一致的確是有效的,但如果會話標識透過cookie傳遞(建議方式),有道理認為,如果攻擊者能取得會話標識,他同時也能取得其它HTTP頭部。由於cookie暴露與瀏覽器漏洞或跨站腳本漏洞相關,受害者需要訪問攻擊者的網站並暴露所有頭部資訊。所有攻擊者要做的只是重建頭部以防止任何對頭部資訊一致性的檢查。
比較好的方法是產生在URL中傳遞一個標記,可以認為這是第二種驗證的形式(雖然較弱)。使用這個方法需要進行一些程式設計工作,PHP中沒有對應的功能。例如,假設標記保存在$token中,你需要把它包含在所有你的應用的內部連結中:
<?php $url = array(); $html = array(); $url['token'] = rawurlencode($token); $html['token'] = htmlentities($url['token'], ENT_QUOTES, 'UTF-8'); ?> <a href="index.php?token=<?php echo $html['token']; ?>">Click Here</a>
為了更方便地管理這個傳遞過程,你可能會把整個請求串放在一個變數中。你可以把這個變數附加到所有連結後面,這樣即便你一開始沒有使用該技巧,今後還是可以很方便地對你的程式碼作出變化。
該標記需要包含不可預測的內容,即使是在攻擊者知道了受害者瀏覽器發出的HTTP頭部的全部資訊也不行。一種方法是產生一個隨機串作為標記:
<?php $string = $_SERVER['HTTP_USER_AGENT']; $string .= 'SHIFLETT'; $token = md5($string); $_SESSION['token'] = $token; ?>
當你使用隨機串時(如SHIFLETT),對它進行預測是不切實際的。此時,捕獲標記將比預測標記更為方便,透過在URL中傳遞標記和在cookie中傳遞會話標識,攻擊時需要同時抓取它們二者。這樣除非攻擊者能夠察看受害者發往你的應用所有的HTTP請求原始資訊才可以,因為在這種情況下所有內容都暴露了。這種攻擊方式實現起來非常困難(所以很罕見),要防止它需要使用SSL。
有专家警告不要依赖于检查User-Agent的一致性。这是因为服务器群集中的HTTP代理服务器会对User-Agent进行编辑,而本群集中的多个代理服务器在编辑该值时可能会不一致。
如果你不希望依赖于检查User-Agent的一致性。你可以生成一个随机的标记:
<?php $token = md5(uniqid(rand(), TRUE)); $_SESSION['token'] = $token; ?>
这一方法的安全性虽然是弱一些,但它更可靠。上面的两个方法都对防止会话劫持提供了强有力的手段。你需要做的是在安全性和可靠性之间作出平衡。
以上就是PHP安全-会话劫持的内容,更多相关内容请关注PHP中文网(www.php.cn)!