PHP安全-會話固定
關(guān)于會話,需要關(guān)注的主要問題是會話標(biāo)識的保密性問題。如果它是保密的,就不會存在會話劫持的風(fēng)險了。通過一個合法的會話標(biāo)識,一個攻擊者可以非常成功地冒充成為你的某一個用戶。
一個攻擊者可以通過三種方法來取得合法的會話標(biāo)識:
l猜測
l捕獲
l固定
PHP生成的是隨機(jī)性很強(qiáng)的會話標(biāo)識,所以被猜測的風(fēng)險是不存在的。常見的是通過捕獲網(wǎng)絡(luò)通信數(shù)據(jù)以得到會話標(biāo)識。為了避免會話標(biāo)識被捕獲的風(fēng)險,可以使用SSL,同時還要對瀏覽器漏洞及時修補(bǔ)。
小提示
要記住瀏覽器會根據(jù)請求中的Set-cookie頭部中的要求對之后所有的請求中都包含一個相應(yīng)的Cookie頭部。最常見的是,會話標(biāo)識會無謂的在對一些嵌入資源如圖片的請求中被暴露。例如,請求一個包含10個圖片的網(wǎng)頁時,瀏覽器會發(fā)出11個帶有會話標(biāo)識的請求,但只有一個是有必要帶有標(biāo)識的。為了防止這種無謂的暴露,你可以考慮把所有的嵌入資源放在有另外一個域名的服務(wù)器上。
會話固定是一種誘騙受害者使用攻擊者指定的會話標(biāo)識的攻擊手段。這是攻擊者獲取合法會話標(biāo)識的最簡單的方法。
在這個最簡單的例子中,使用了一個鏈接進(jìn)行會話固定攻擊:
<a >Click Here</a>
另外一個方法是使用一個協(xié)議級別的轉(zhuǎn)向語句:
<?php
header(’Location: http://example.org/index.php?PHPSESSID=1234’);
?>
這也可以通過Refresh頭部來進(jìn)行,產(chǎn)生該頭部的方法是通過真正的HTTP頭部或meta標(biāo)簽的http-equiv屬性指定。攻擊者的目標(biāo)是讓用戶訪問包含有攻擊者指定的會話標(biāo)識的URL。這是一個基本的攻擊的第一步,完整的攻擊過程見圖4-3所示。
Figure 4-3. 使用攻擊者指定的會話標(biāo)識進(jìn)行的會話固定攻擊
如果成功了,攻擊者就能繞過抓取或猜測合法會話標(biāo)識的需要,這就使發(fā)起更多和更危險的攻擊成為可能。
為了更好地使你理解這一步驟,最好的辦法是你自己嘗試一下。首先建立一個名為fixation.php的腳本:
<?php
session_start();
$_SESSION[’username’] = ’chris’;
?>
確認(rèn)你沒有保存著任何當(dāng)前服務(wù)器的cookies,或通過清除所有的cookies以確保這一點(diǎn)。通過包含PHPSESSID的URL訪問fixation.php:
http://example.org/fixation.php?PHPSESSID=1234
它建立了一個值為chris的會話變量username。在檢查會話存儲區(qū)后發(fā)現(xiàn)1234成為了該數(shù)據(jù)的會話標(biāo)識:
$ cat /tmp/sess_1234
username|s:5:'chris';
建立第二段腳本test.php,它在$_SESSION[‘username’]存在的情況下即輸入出該值:
<?php
session_start();
if (isset($_SESSION[’username’]))
{
echo $_SESSION[’username’];
}
?>
在另外一臺計(jì)算機(jī)上或者在另一個瀏覽器中訪問下面的URL,同時該URL指定了相同的會話標(biāo)識:
http://example.org/test.php?PHPSESSID=1234
這使你可以在另一臺計(jì)算機(jī)上或?yàn)g覽器中(模仿攻擊者所在位置)恢復(fù)前面在fixation.php中建立的會話。這樣,你就作為一個攻擊者成功地劫持了一個會話。
很明顯,我們不希望這種情況發(fā)生。因?yàn)橥ㄟ^上面的方法,攻擊者會提供一個到你的應(yīng)用的鏈接,只要通過這個鏈接對你的網(wǎng)站進(jìn)行訪問的用戶都會使用攻擊者所指定的會話標(biāo)識。
產(chǎn)生這個問題的一個原因是會話是由URL中的會話標(biāo)識所建立的。當(dāng)沒有指定會話標(biāo)識時,PHP就會自動產(chǎn)生一個。這就為攻擊者大開了方便之門。幸運(yùn)的是,我們以可以使用session_regenerate_id( )函數(shù)來防止這種情況的發(fā)生。
<?php
session_start();
if (!isset($_SESSION[’initiated’]))
{
session_regenerate_id();
$_SESSION[’initiated’] = TRUE;
}
?>
這就保證了在會話初始化時能有一個全新的會話標(biāo)識??墒牵@并不是防止會話固定攻擊的有效解決方案。攻擊者能簡單地通過訪問你的網(wǎng)站,確定PHP給出的會話標(biāo)識,并且在會話固定攻擊中使用該會話標(biāo)識。
這確實(shí)使攻擊者沒有機(jī)會去指定一個簡單的會話標(biāo)識,如1234,但攻擊者依然可以通過檢查cookie或URL(依賴于標(biāo)識的傳遞方式)得到PHP指定的會話標(biāo)識。該流程如圖4-4所示。
該圖說明了會話的這個弱點(diǎn),同時它可以幫助你理解該問題涉及的范圍。會話固定只是一個基礎(chǔ),攻擊的目的是要取得一個能用來劫持會話的標(biāo)識。這通常用于這樣的一個系統(tǒng),在這個系統(tǒng)中,攻擊者能合法取得較低的權(quán)限(該權(quán)限級別只要能登錄即可),這樣劫持一個具有較高權(quán)限的會話是非常有用的。
如果會話標(biāo)識在權(quán)限等級有改變時重新生成,就可以在事實(shí)上避開會話固定的風(fēng)險:
<?php
$_SESSION[’logged_in’] = FALSE;
if (check_login())
{
session_regenerate_id();
$_SESSION[’logged_in’] = TRUE;
}
?>
Figure 4-4. 通過首先初始化會話進(jìn)行會話固定攻擊
小提示
我不推薦在每一頁上重新生成會話標(biāo)識。雖然這看起來確實(shí)是一個安全的方法。但與在權(quán)限等級變化時重新生成會話標(biāo)識相比,并沒有提供更多的保護(hù)手段。更重要的是,相反地它還會對你的合法用戶產(chǎn)生影響,特別是會話標(biāo)識通過URL傳遞時尤甚。用戶可能會使用瀏覽器的訪問歷史機(jī)制去訪問以前訪問的頁面,這樣該頁上的鏈接就會指向一個不再存在的會話標(biāo)識。
如果你只在權(quán)限等級變化時重新生成會話標(biāo)識,同樣的情況也有可以發(fā)生,但是用戶在訪問權(quán)限變更前的頁面時,不會因?yàn)闀拋G失而奇怪,同時,這種情況也不常見。
相關(guān)文章:
1. 基于javaweb+jsp實(shí)現(xiàn)學(xué)生宿舍管理系統(tǒng)2. 如何封裝一個Ajax函數(shù)3. 多級聯(lián)動下拉選擇框,動態(tài)獲取下一級4. ASP.NET MVC實(shí)現(xiàn)樹形導(dǎo)航菜單5. 什么是JWT超詳細(xì)講解6. python 在mysql中插入null空值的操作7. Python爬蟲基礎(chǔ)之初次使用scrapy爬蟲實(shí)例8. .NET Core中RabbitMQ使用死信隊(duì)列的實(shí)現(xiàn)9. Python如何telnet到網(wǎng)絡(luò)設(shè)備10. 關(guān)于html嵌入xml數(shù)據(jù)島如何穿過樹形結(jié)構(gòu)關(guān)系的問題
