關於會話,需要關注的主要問題是會話標識的保密性問題。如果它是保密的,就不會存在會話劫持的風險了。透過一個合法的會話標識,一個攻擊者可以非常成功地冒充成為你的某一個使用者。
一個攻擊者可以透過三種方法來取得合法的會話識別:
l 猜測
l 捕獲
l 固定
PHP產生的是隨機性很強的會話標識,所以被猜測的風險是不存在的。常見的是透過擷取網路通訊資料以獲得會話標識。為了避免會話標識被捕獲的風險,可以使用SSL,同時也要對瀏覽器漏洞及時修補。
小提示
要記住瀏覽器會根據請求中的Set-cookie頭部中的要求對之後所有的請求中都包含一個相應的Cookie頭部。最常見的是,會話標識會無謂的在對一些嵌入資源如圖片的請求中被暴露。例如,請求一個包含10個圖片的網頁時,瀏覽器會發出11個帶有會話標識的請求,但只有一個是有必要帶有標識的。為了防止這種無謂的暴露,你可以考慮把所有的嵌入資源放在有另外一個網域的伺服器上。
會話固定是一種誘騙受害者使用攻擊者指定的會話標識的攻擊手段。這是攻擊者獲取合法會話標識的最簡單的方法。
在這個最簡單的例子中,使用了一個連結進行會話固定攻擊:
<a href="http://example.org/index.php?PHPSESSID=1234">Click Here</a>
另一個方法是使用一個協定層級的轉向語句:
<?php header('Location: http://www.php.cn/'); ?>
這也可以透過Refresh頭部來進行,產生該頭部的方法是透過真正的HTTP頭部或meta標籤的http-equiv屬性指定。攻擊者的目標是讓使用者存取包含有攻擊者指定的會話標識的URL。這是一個基本的攻擊的第一步,完整的攻擊過程見圖4-3所示。
Figure 4-3. 使用攻擊者指定的會話標識進行的會話固定攻擊
如果成功了,攻擊者就能繞過抓取或猜測合法會話標識的需要,這就使發起更多和更危險的攻擊成為可能。
為了更好地使你理解這一步驟,最好的方法是你自己嘗試。先建立一個名為fixation.php的腳本:
<?php session_start(); $_SESSION['username'] = 'chris'; ?>
確認你沒有保存任何目前伺服器的cookies,或透過清除所有的cookies以確保這一點。透過包含PHPSESSID的URL造訪fixation.php:
http://www.php.cn/
它建立了一個值為chris的會話變數username。檢查會話儲存區後發現1234成為了該資料的會話識別:
$ cat /tmp/sess_1234 username|s:5:"chris";
建立第二段腳本test.php,它在$_SESSION['username'] 存在的情況即輸入出該值:
<?php session_start(); if (isset($_SESSION['username'])) { echo $_SESSION['username']; } ?>
在另外一台计算机上或者在另一个浏览器中访问下面的URL,同时该URL指定了相同的会话标识:
http://www.php.cn/
这使你可以在另一台计算机上或浏览器中(模仿攻击者所在位置)恢复前面在fixation.php中建立的会话。这样,你就作为一个攻击者成功地劫持了一个会话。
很明显,我们不希望这种情况发生。因为通过上面的方法,攻击者会提供一个到你的应用的链接,只要通过这个链接对你的网站进行访问的用户都会使用攻击者所指定的会话标识。
产生这个问题的一个原因是会话是由URL中的会话标识所建立的。当没有指定会话标识时,PHP就会自动产生一个。这就为攻击者大开了方便之门。幸运的是,我们以可以使用session_regenerate_id( )函数来防止这种情况的发生。
<?php session_start(); if (!isset($_SESSION['initiated'])) { session_regenerate_id(); $_SESSION['initiated'] = TRUE; } ?>
这就保证了在会话初始化时能有一个全新的会话标识。可是,这并不是防止会话固定攻击的有效解决方案。攻击者能简单地通过访问你的网站,确定PHP给出的会话标识,并且在会话固定攻击中使用该会话标识。
这确实使攻击者没有机会去指定一个简单的会话标识,如1234,但攻击者依然可以通过检查cookie或URL(依赖于标识的传递方式)得到PHP指定的会话标识。该流程如图4-4所示。
该图说明了会话的这个弱点,同时它可以帮助你理解该问题涉及的范围。会话固定只是一个基础,攻击的目的是要取得一个能用来劫持会话的标识。这通常用于这样的一个系统,在这个系统中,攻击者能合法取得较低的权限(该权限级别只要能登录即可),这样劫持一个具有较高权限的会话是非常有用的。
如果会话标识在权限等级有改变时重新生成,就可以在事实上避开会话固定的风险:
<?php $_SESSION['logged_in'] = FALSE; if (check_login()) { session_regenerate_id(); $_SESSION['logged_in'] = TRUE; } ?>
Figure 4-4. 通过首先初始化会话进行会话固定攻击
小提示
我不推荐在每一页上重新生成会话标识。虽然这看起来确实是一个安全的方法。但与在权限等级变化时重新生成会话标识相比,并没有提供更多的保护手段。更重要的是,相反地它还会对你的合法用户产生影响,特别是会话标识通过URL传递时尤甚。用户可能会使用浏览器的访问历史机制去访问以前访问的页面,这样该页上的链接就会指向一个不再存在的会话标识。
如果你只在权限等级变化时重新生成会话标识,同样的情况也有可以发生,但是用户在访问权限变更前的页面时,不会因为会话丢失而奇怪,同时,这种情况也不常见。
以上就是PHP安全-会话固定的内容,更多相关内容请关注PHP中文网(www.php.cn)!