1. 程式人生 > >來談談網路安全,關於Session冒名頂替和cookie防篡改的問題

來談談網路安全,關於Session冒名頂替和cookie防篡改的問題

做網站難免要面對安全性的問題,諸如sql注入拉,cookie冒名拉,等等,sql注入算是老生常談,翻翻舊賬有不少優秀的帖子在說明這個問題,所以我們來說說Session冒名頂替的風險以及應對的辦法。
首先要說Session冒名頂替,就得說說Session的原理。Session是一個在伺服器端保持會話的機制,其實在Http協議裡並沒有規定 Session這個東西,所以他的實現方式就有點千奇百怪,不同的Web框架下Session的實現機制都是不一樣的。但是原理都是大同小異的,這裡普遍應用的機制是通過Cookie來儲存一個會話的票據(也就是SessionID),服務端在cookie裡取得SessionID後就去儲存 Session的後端(可以是程序裡,資料庫,或者其他任何可以儲存資料的東西,包括檔案)去獲取這個會話的資料。

我們用一個抓包工具來獲取一段資料看看,如下:
GET /w3/global/j/global.js HTTP/1.1 
Accept: */* 
Referer: http://www.jiayuan.com/login/index.php?pre_url=/usercp 
Accept-Language: zh-cn 
Accept-Encoding: gzip, deflate 
User-Agent: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1; EmbeddedWB 14.52 from: http://www.bsalsa.com/ EmbeddedWB 14.52) 

Host: images.jiayuan.com 
Connection: Keep-Alive 
Cookie: SESSION_HASH=aa200d999de428f8e84ad56f4fc0afb9ac88fb78; stadate1=25727411; myloc=53%7C5301; myage=24; mysex=m; myuid=25727411; myincome=30; last_login_time=1277561249; new_msg=0; pop_1268278480=1277575662747; pop_time=1277561290653

標紅字的地方就是SessionID了,當然ASP.NET有一種Cookieless的機制,是把這個ID放在url裡傳遞。

這裡就有一個問題,這個ID在非SSL的環境下提交是明文的,所以如果這個ID被竊取,然後就可以冒名頂替別人的身份了(注:大多數框架的設計中 Session一旦被建立後,SessionID的值就固定了,不會變)。
這涉及到Web開發中的一個說法,就是客戶端的任何輸入都是不可信的,所以Cookie作為在客戶端保留的資料,在沒有防篡改機制的保護下,其內容也是不可信任的。一旦信任了這樣的資料,就會存在一個安全上的隱患。
那麼如何來防範呢,這裡我們需要實現cookie防篡改的功能。Cookie防篡改功能的原理很簡單。假設我有一個值要寫入Cookie
key="user_name" value="alexander"
如果需要防止這個值被篡改成其他的值是不可能的,因為cookie已經寫到了客戶端,別人可以隨意的改,伺服器是沒辦法阻止的,但是我們可以用防篡改的機制來讓伺服器知道cookie的值被篡改過。所以在向客戶端傳送cookie的時候就不能原樣發回去了,我們在Cookie的值後面跟上一段防篡改的驗證串,整個作為一個整體傳送到客戶端。所以客戶端得到的cookie可能就是這個樣子:
user_name=alexander|ab95ef23cc6daecc475de
用|分割的後面部分就是驗證串,也可以叫防篡改驗證串。它是這樣生成的, DES(cookie的內容+鹽值)
也可以用 MD5(cookie內容+金鑰)也可以是SHA1(cookie內容+金鑰),這裡的金鑰只有站點本身知道,如果這個都洩漏了那就真完蛋了。這個值在伺服器接收到Cookie以後,就可以用Cookie的內容+金鑰重新計算一次驗證串,和提交上來的做比對,如果是一致的,我們就認為cookie沒有被篡改,反之,cookie肯定被篡改過,我們就不要相信這一次提交。如果所有的Cookie都經過防篡改驗證,那麼也就不用擔心SessionID被冒名頂替的事情發生了。
ASP.NET的sessionID我不知道是否有這個機制(汗顏,以前一直沒關注過)不過Cookie是沒有的,所以大家可以自己動手來增加這個功能,這樣對於提高站點的安全性是有非常大的幫助的。