[說(shuō)明: 本文為 http://www.smithfox.com/?e=32 原創(chuàng), 轉(zhuǎn)載請(qǐng)注明原文, 謝謝]
session的安全有兩層意思:
1> 對(duì)最終客戶來(lái)說(shuō), 不會(huì)因?yàn)閟ession的share和造成混亂, 使end-user的信息泄漏以及其他安全問(wèn)題
2> 對(duì)系統(tǒng)本身來(lái)說(shuō), 不會(huì)因?yàn)橛衕acker通過(guò)模擬sessionid和cookie來(lái)獲取server信任進(jìn)而進(jìn)行惡意破壞
讓我們逐層解釋和展開(kāi)問(wèn)題:
1> 首先說(shuō)明, 本文所有session專指Servlet HttpSession
2>
后臺(tái)Session和Browser之間通過(guò)JSESSIONID來(lái)關(guān)聯(lián), JSESSIONID是Servlet標(biāo)準(zhǔn),也是關(guān)鍵字,
Servle規(guī)定Browser用Mem Cookie來(lái)存儲(chǔ)JSESSIONID, 注意并不是disk
cookie.一旦瀏覽器關(guān)閉后JSESSIONID就從PC消失, 更加安全.
3> Session也是一種很好的安全認(rèn)證機(jī)制, 后臺(tái)會(huì)標(biāo)識(shí)session是不是已經(jīng)被認(rèn)證了, 如果是,就不會(huì)讓用戶再輸入password. JSESSIONID可以被理解成為一個(gè)已經(jīng)認(rèn)證的key, 所以Session有安全問(wèn)題.
4> Servlet容器不會(huì)構(gòu)造相同的JSESSIONID, 客戶端也很難預(yù)期JSESSIONID
5> HTTPS SSL等技術(shù)可以防止網(wǎng)絡(luò)傳輸中有人惡意篡改JSESSIONID
6> 禁用Cookie的情況JSESSIONID就必須用URLRewrite. 我們可以通過(guò)對(duì)URL本身采用摘要算法,自認(rèn)證來(lái)防止惡意篡改JSESSIONID.
比如: http://www.smithfox.com/abc?x=x&y=y&JSESSIONID=sdfdfsdfsdfsdfsdf&HWD=4FE23AD9892C
HWD的值是對(duì)整個(gè)URL的一個(gè)摘要算法, 如果有人改動(dòng)了URL,這個(gè)HWD值就對(duì)不上了, 前提應(yīng)該是這個(gè)算法別人不知道的.
7> 用戶在自己的PC上肯定是可以看到當(dāng)前的JSESSIONID的, 就象就你在自己的日記中看到了自己備忘的password一樣, 這個(gè)不是技術(shù)安全問(wèn)題.
8>
一臺(tái)機(jī)器有多個(gè)自然人在使用, 出現(xiàn)的JSESSIONID欺騙, 應(yīng)該沒(méi)有技術(shù)辦法可以解決.
只能是end-user自己小心,用完就關(guān)閉Browser. 我想這應(yīng)該是在情理之中的事, 你是合租被盜應(yīng)該是怪不得小區(qū)保安的,
也是需要自己平時(shí)提高防盜意識(shí),呵呵.
9> 最近看到Tomcat7有個(gè)新的特性說(shuō)是支持"防JSESSIONID劫持", 這個(gè)需要更多了解.
10> User和Session的關(guān)系.
Session是只認(rèn)JSESSIONID不認(rèn)人的, 包括自然人和系統(tǒng)Account. 這個(gè)問(wèn)題比較搞.
我們用EndUser來(lái)表示自然人, User-Account表示系統(tǒng)帳號(hào), 我們分析以下幾種情況
10.1> 兩個(gè)EndUser共用一個(gè)UserAccount并且在同一臺(tái)PC, 這個(gè)混亂不是技術(shù)問(wèn)題, 大家都可以理解
10.2> 兩個(gè)EndUser分別使用不同的UserAccount在同一臺(tái)PC, 這個(gè)是合租情況, 造成混亂不一定是技術(shù)問(wèn)題
10.3> 某EndUser有兩個(gè)UserAccount在同一臺(tái)PC上, 我們需要考慮JSESSIONID在client端可以會(huì)混亂的問(wèn)題.
因?yàn)椴煌臑g覽器對(duì)于Cookie share的策略不同, 我們按程序設(shè)計(jì)必須按最容易出問(wèn)題的Case想,比如IE8.
無(wú)論你是IE多窗口還是多TAB都是Share Cookie的. 所以總的指導(dǎo)方針是在client端做一些機(jī)制不允許用戶這么做.
Google
的gmail就是這么做的, 你可以一臺(tái)機(jī)器上用IE打開(kāi)兩個(gè)不同的gmail
account(兩個(gè)窗口或是兩個(gè)TAB都行),點(diǎn)新email或是其他需要和后臺(tái)交互的行為時(shí),gmail會(huì)退出一個(gè),提示讓你重新login并且
gmail account已經(jīng)固定為后輸入的User-Account.
具體在Client怎么防止兩個(gè)Account還需高手指點(diǎn).
10.4> 某EndUserA用自己的UserAccountA先已經(jīng)login,再訪問(wèn)另一個(gè)UserAccountB的資源,而且該資源是需要訪問(wèn)密碼的.
這種情況,往往因?yàn)楹笈_(tái)Session設(shè)計(jì)的層次不清晰,造成了UserAccountA無(wú)需Password就直接訪問(wèn)到了UserAccountB的資源. 而且這個(gè)解決方案不能放在Client端, 因?yàn)樵L問(wèn)UserAccountB的資源可能就是一個(gè)在Email中的Link,這個(gè)click動(dòng)作客戶端程序JavaScript是無(wú)法攔截的.
10.5> 總結(jié)來(lái)說(shuō):
11> 從第10>點(diǎn)可以看出, session和自然人或是UserAccount有著千絲萬(wàn)縷的聯(lián)系,但不是所有的系統(tǒng)只有User這一層業(yè)務(wù)概念,所以我們需要理解后臺(tái)的Session分劃和設(shè)計(jì)好Session.Attribute層次.
我
們以一個(gè)假設(shè)業(yè)務(wù)模型為例說(shuō)明問(wèn)題: 這是一個(gè)只面向企業(yè)的圖片共享web服務(wù), 可以為多個(gè)公司(企業(yè))提供服務(wù), 用戶必須屬于某一個(gè)公司,
用戶可以創(chuàng)建"圖片分組", 圖片分組可以設(shè)置為private(需要密碼訪問(wèn)), 也可以直接公開(kāi). 圖片分組是公司財(cái)產(chǎn),
user可以創(chuàng)建"圖片分組", 但是圖片分組資源是歸屬公司, 同一公司內(nèi)部的所有user可以直接訪問(wèn)圖片分組(如果是公開(kāi)),
也可以通過(guò)password(如果需要)訪問(wèn)圖片分組.
這個(gè)業(yè)務(wù)模型中, 既有比User更高層的概念, 比如公司. 也有比User更底的概念, 比如用戶的上傳圖片分組(imageGroup).
11.1> 不同的war包部署在tomcat,不同的war包之間的session是不會(huì)混亂的, 這個(gè)是由tomcat架構(gòu)決定的. 另他的沒(méi)有做過(guò)調(diào)查, 也有可能是Servlet標(biāo)準(zhǔn), 有高手可以幫確認(rèn)一下.
11.2> 多個(gè)公司又是運(yùn)行在同一個(gè)tomcat application內(nèi), 怎么防止不同公司之間的session混亂
可以采用類似于防止重復(fù)提交的技術(shù), 首先做一個(gè)優(yōu)先級(jí)很高的filter, 每次reqeust和response都需要經(jīng)過(guò)這個(gè)filter
在
所有l(wèi)ogin模塊, 設(shè)置一個(gè)ticket cookie,寫入當(dāng)前company信息, 每個(gè)reqeust到達(dá)的第一步就是檢測(cè)client
cookie和當(dāng)前的URL信息, 以及session信息是否一致,
如果enduser是從一個(gè)company中click了一個(gè)其他company的link, 該filter就會(huì)發(fā)現(xiàn)ticket信息不一致,
然后就強(qiáng)制logout, 再次讓user login. 并且每次response時(shí)做ticket的改動(dòng), 使client無(wú)法模擬
11.3> 怎么防止imageGroup信息混亂
Session本身是一個(gè)集合, 具體還是使用session.attribute["key"]
Session本身是User level的, 對(duì)于低于User level的信息, 需要好好規(guī)劃attribute key
想像這樣的case:
有兩個(gè)imageGroup, 一個(gè)是public的, 一個(gè)是需要password的,
http://www.smithfox.com/companyIBM/public_images/
http://www.smithfox.com/companyIBM/password_images/
后臺(tái)對(duì)imageGroup輸入密碼邏輯的偽代碼如下:
boolean needpasswd = true;
if(session.getAttribute("NEED_PASSWORD") == null){
session.setAttribute("NEED_PASSWORD", needpasswd);
boolean needpasswd = 一個(gè)很耗時(shí)很復(fù)雜的驗(yàn)證函數(shù)(user, imageGroup, xxx);
} else{
needpasswd = session.getAttribute("NEED_PASSWORD");
}
if (needpasswd ){
showPasswordDialog() ;
}
看出什么問(wèn)題沒(méi)?
應(yīng)該將上面的代碼中的所有attribute key改成 "NEED_PASSWORD"+{imageGroupID}
否則用戶只要先看了一個(gè)public后, 后面的所有圖片分組都無(wú)需passwd就可以訪問(wèn)了, 即使這個(gè)imageGroup是private的.
13> 在用session之前一定需要檢查是否真的一定需要session來(lái)解決, 比如只是想傳value到JSP page, request.setAttribte()更適合
14> 比較小而多的業(yè)務(wù)對(duì)象,如果必須save在session一定要及時(shí)removeAttribute否則session用的內(nèi)存會(huì)暴漲.
因?yàn)镾ession不會(huì)因?yàn)榭蛻舳瞬挥昧耍蜁?huì)自動(dòng)清理,而是必須到SessionTimeOut才會(huì),如果在SessionTimeOut期間內(nèi)有很多的對(duì)象在Session內(nèi),就會(huì)有問(wèn)題。所以需要即時(shí)清理已經(jīng)不用的Session.Attribute
15> Cookie和Session一樣, 同樣需要注意 cookie key的層次問(wèn)題,以及過(guò)期問(wèn)題,domain, path問(wèn)題等等