Session 相關(guān)知識

摘自 <<精通 Java Web 開發(fā)>>

1 Session的作用

Session 用于維護同一客戶端發(fā)送的多個請求的狀態(tài)驮捍。

由于 HTTP 協(xié)議是無狀態(tài)協(xié)議俗他,從服務器的角度來看娃肿,客戶端瀏覽器與服務器間建立起 socket 連接之后欠橘,就是一個請求的開始加勤,而服務器發(fā)送最后一個數(shù)據(jù)包到客戶端,然后關(guān)閉連接鲤嫡。之后就沒有客戶端與服務器間的連接了逛球,再之后即使是相同客戶端過來的請求,也是通過一條新的連接發(fā)送的屯远。這樣便無法區(qū)分當前請求和以前請求是否是同一個客戶端發(fā)送過來的蔓姚。

如果從現(xiàn)實生活中來看,就好比是去買東西慨丐,每次只能買一件坡脐,買了結(jié)賬就相當于獲取了請求。然后再買再結(jié)賬房揭。备闲。。這樣很麻煩捅暴。所以好的辦法是將東西放入購物車恬砂,一起結(jié)賬。不必每次都去結(jié)賬蓬痒。

購物車在這里起到的就是一個狀態(tài)維護的角色泻骤,這樣的任務也是Session想達成的。

Session的一些典型應用場景:

  • 記錄用戶
  • 支持工作流

實現(xiàn)Session的兩種途徑:

  • Session cookie
  • URL重寫

不過總體流程都是:

B第一次提出請求 --->服務器收到請求梧奢,若客戶端沒有發(fā)送Session Cookie過來狱掂,就認為它是第一次請求 ---->通過Session機制為客戶端分配一個Session,并生成對應的Session ID --->將生成的ID返還給客戶端(通過Cookie機制或重寫URL加入Session ID)

相同B的以后請求 --->服務器收到亲轨,檢查有 Session趋惨,查詢 Session ID ---> 獲取對應的存放在服務器的 Session --->進行狀態(tài)維護。

而 Session Cookie 或重寫的 URL 只負責攜帶 Session ID惦蚊,Session 對象由服務器存儲器虾。

當設(shè)置JSP中page指令的session屬性為false時,訪問該頁面就不會產(chǎn)生Session Cookie了养筒。
<%@ page session="false" %>
并且可以在web.xml中對session cookie的生命期進行設(shè)置曾撤。
默認的生命期是當本次會話結(jié)束(關(guān)閉瀏覽器)

2 安全問題

session的使用中很大可能受到session劫持端姚。

  • 復制session晕粪,別人就可以通過這個session id訪問到你的內(nèi)容了。
  • 讓別人通過一個構(gòu)造的夾雜由session id的url訪問渐裸,則可以通過相同id來之后查看內(nèi)容巫湘。
  • 跨站腳本攻擊是使用javascript腳本來讀取本地cookie,然后再在自己本地構(gòu)造一個仿冒的session cookie(或使用url內(nèi)嵌session id)昏鹃。(防范就是可以使用httponly, chrome中的這個選項解釋地不錯:Accessible to script:No (HttpOnly)尚氛,即啟用httponly就是不允許腳本訪問該cookie,而只能是url或鏈接才可以訪問洞渤。
  • 中間人攻擊:它是通過一個中間人觀察到請求和響應阅嘶。不過使用HTTPS可以很好防范這樣的偷窺。。讯柔。不過一個突出問題是當網(wǎng)站非純HTTPS(即使是從HTTP直接重定向HTTPS)抡蛙,第一次請求的Session也是通過HTTP發(fā)送,而非加密的HTTPS魂迄。

最佳防范:

  • 使用SSL/TLS Session ID:SSL協(xié)議定義了它自己的Session id類型粗截。SSL Session ID在SSL握手的時候建立。然后被用于以后的請求捣炬,它被用于決定使用哪個key來加密和解密熊昌。而且SSL Session ID即不使用Cookie存儲,也不使用URL內(nèi)嵌湿酸。(具體參見RFC2246)這樣也就避免了使用Cookie或URL內(nèi)嵌所造成的安全問題婿屹。

但之前版本的JAVA EE實現(xiàn)SSL Session十分困難,直到EE 6才提供了一個簡單的途徑:使用secure標志的Cookie推溃。它就是SSL Session Cookie选泻。不過它要求你的站點必須始終使用的是HTTPS協(xié)議。

使用SSL Session的另外一個問題是web容器必須能夠支撐SSL交流美莫。如果架構(gòu)的前端使用的是一個web服務器或者負載均衡服務器页眯,則web容器是無法得知請求的SSL Session ID的。在這樣的分布式環(huán)境下使用SSL Session ID厢呵,則用戶請求就還必須總是被路由到web容器(而不是去攔截區(qū)分動態(tài)靜態(tài)請求)窝撵。

最后,SSL Session ID的生命期可能很長襟铭,也可能很短碌奉,這是基于服務器和瀏覽器決定的。所以目前它仍然無法大規(guī)模替代HTTP Session ID寒砖。

3 在服務器端Session對象中存放數(shù)據(jù)

首先來看看如何在web.xml中配置Session:

<session-config>
// 略
</session-config>

4 Session的其他用途:

用戶登陸:可以在session中加入已登陸的session attribute赐劣。

用戶登出:session的invalid方法。

5 使用Listener來監(jiān)聽session變化

實現(xiàn)HttpSessionXXXListener接口哩都,然后在web.xml中寫listener標簽或為該類添加WebListener注解即可魁兼。

監(jiān)聽Session創(chuàng)建銷毀,session屬性改變漠嵌,id改變等等咐汞。(其中改變id是通過request的changesessionid來做的)

獲取session列表的方案:

由于沒有提供獲取全部session的途徑,所以只能是當服務器開啟后監(jiān)聽session的創(chuàng)建儒鹿,然后將session放入一個數(shù)據(jù)結(jié)構(gòu)中保持化撕。以便查詢了。约炎。植阴。編程時貌似是只有這樣的蟹瘾。

6 利用Session來支持分布式應用

要搞企業(yè)級應用,就需要使用分布式掠手∪惹郏可以讓應用得到很好支持。前端可以由很多個不同的負載均衡惨撇,也有很多應用服務器伊脓,但是數(shù)據(jù)服務器必須是同步的。分布式的數(shù)據(jù)的同步問題魁衙,還是抽象成多個讀者一個寫者的讀者寫者問題吧报腔。

但搞分布式的一個挑戰(zhàn)就是:在不同應用服務器上運行的應用組成部分之間的信息交換問題。所以之前出現(xiàn)了許多的解決方案剖淀,比如AMQP纯蛾,JMS,MSMQ等協(xié)議纵隔,都是解決這個問題的翻诉。當然,分布式應用需要解決的問題絕不僅僅只有這一個捌刮。

下面先來看看如何在分布式應用中使用Session ID碰煌。

6.1 在分布式應用中使用Session ID們 :)

目前的情況是:一個特定的Session只會存在與一個單獨的應用服務器內(nèi)存中,并且作為一個單獨的對象存在绅作。

在負載均衡服務器和應用服務器協(xié)同工作的場景下芦圾,可能同一客戶端的兩次連續(xù)請求會被分發(fā)到不同的應用服務器中處理,造成第一個請求被服務器A分配一個Session ID俄认,第二個請求被送達服務器時个少,攜帶的是這個服務器上不存在的Session ID,故第二個服務器又重新為第二個請求分配新的Session ID眯杏。也就是說每次請求被送到不同服務器上夜焦,只要該請求攜帶的Session ID不是這個服務器分配的,則請求相對于服務器而言就是新的一個客戶的請求岂贩,那這樣的話要Session有毛用茫经。。河闰。

一個解決方案是:sticky session科平。意思是讓負載均衡機制能夠識別session id并將對應請求轉(zhuǎn)發(fā)給對應的分配session id的應用服務器處理。這樣的機制也是比較容易實現(xiàn)的姜性,比如先讓負載均衡服務器可以讀取session-cookie,這樣來判斷該cookie對應的應用服務器從而進行轉(zhuǎn)發(fā)髓考〔磕睿或者是負載均衡服務器增加自己的session-cookie到響應中。(不懂)

但這個解決方案存在問題:阻礙使用SSL/HTTPS的使用。因為使用它們后儡炼,負載均衡服務器就無法再對請求進行修改或截獲了妓湘。但是可以讓負載均衡服務器來實現(xiàn)HTTPS/SSL通信。

Tomcat環(huán)境實現(xiàn)負載均衡的措施是在前端使用一個Apache HTTPD或IIS作為web服務器乌询,將請求進行負載均衡到后端的Tomcat服務器實例上榜贴。而Tomcat Connector 提供了Tomcat與web服務器間的通信連接。Connector的mod_jk組件是Apache HTTPD的一個模塊妹田,該模塊將動態(tài)請求轉(zhuǎn)發(fā)給后端Tomcat服務器唬党,并提供sticky session支持(即上面說的將對應session的請求發(fā)送給對應的服務器,而利用的就是Session cookie中的Session ID們鬼佣。驶拱。。)晶衷。

與mod_jk類似蓝纲,IIS上的connector有一個isapi_redirect組件,也是提供相似功能晌纫。

當請求數(shù)目進一步提升時税迷,還可以直接在web服務器前端加入一個簡單的輪詢負載均衡服務器,將請求分配給不同的web服務器(這些web服務器再將負載進一步轉(zhuǎn)發(fā)給不同的應用服務器)锹漱。

上面提到的這種分層結(jié)構(gòu)可以實現(xiàn)很高的擴展性翁狐。

connector使用的是Tomcat中的一個概念:session id jvmroute。這個概念要解決的問題就是將哪個請求轉(zhuǎn)發(fā)給哪個對應的Tomcat實例凌蔬,而利用的正是Session ID露懒。

比如有如下的Session id:abc123(實際的當然比這個長得多,這里僅演示)

在負載均衡環(huán)境下砂心,后端有多臺Tomcat應用服務器(Tomcat實例)懈词,每個Tomcat實例都會擁有一個jvmroute配置(在Tomcat的conf/server.xml文件的<Connector>元素中配置)。而這個jvmroute的值會被附加到每個session id末尾辩诞。

比如此時有三臺Tomcat實例坎弯,每個分別對應jvmroute值為tcin01,tcin02译暂,tcin03抠忘。

不同Tomcat實例生成的session ID就會是如下:

abc123.tcin02      //比如第二臺,就是sessionID.jvmroute的形式

這種情況下當請求到達后的話外永,Connector(HTTPD服務器的mod_jk模塊或IIS的isapi_redirect模塊)就能夠根據(jù)請求攜帶的session id來對應地將請求轉(zhuǎn)發(fā)到不同Tomcat實例崎脉。

若應用是使用HTTPS的,則需要讓web服務器來驗證請求并進行加密解密工作伯顶。而使用mod_jk或isapi_redirect模塊好處是:它們能夠訪問SSL Session ID并將ID傳送給Tomcat囚灼。Tomcat也可以替換為GlassFish(其他不變)骆膝。

6.2 理解Session復制和失效備緩

sticky session的一個主要問題是:它可以實現(xiàn)高擴展性,但無法實現(xiàn)高可用性灶体。

比如當創(chuàng)建某個session的Tomcat掛掉之后阅签,這個對應的session的用戶就相對于又成了新用戶了,又需要如重新登陸等蝎抽,更有可能是用戶丟失沒有保存的數(shù)據(jù)政钟。正因為如此,下面提出一種解決辦法:session的復制樟结。簡單來說就是將每個應用服務器上的session都復制养交,這樣所有服務器上的所有session對所有服務器都可用。

而在應用用打開session復制功能也很簡單:在web.xml中加入一句 <distributable />即可狭吼。

這個標簽告訴web容器层坠,若是在分布式環(huán)境下的話,就進行session復制刁笙。(如果某個session發(fā)生改變破花,則這個改變也會重新被復制到每個應用服務器中。

不過設(shè)置這個標簽只是為了向web容器說明該應用支持session復制疲吸。而實際使用時還需要配置web容器座每,開啟容器的session復制機制。

但在開啟了session復制的環(huán)境下摘悴,就必須額外小心地進行session的屬性的設(shè)置或改變等操作了峭梳。(比如session中的某個屬性內(nèi)存放的是一個集合,對這個集合中的元素的改變并不會觸發(fā)session的重新復制蹂喻。故要對其中集合進行操作的話葱椭,最好是在外部操作集合,然后進行一次setAttribute設(shè)置該集合到session中口四,這樣才會觸發(fā)重新復制的動作)

另外要注意一個監(jiān)聽器HttpSessionActivationListener孵运,這個監(jiān)聽器用于監(jiān)聽Session的序列化(因為復制時需要先序列化再反序列化),當進行序列化動作時就會觸發(fā)監(jiān)聽器的sessionWillPassive方法蔓彩。而當該序列再在另外容器中被反序列化時治笨,會觸發(fā)監(jiān)聽器的sessionDidActivate方法。

最后要指出的是:sticky session id機制和Session復制機制并不互斥赤嚼。實際上二者經(jīng)常結(jié)合使用以滿足session的失效備緩旷赖。(session仍然被復制到每個容器,當某容器掛掉后更卒,該容器對應的請求會被轉(zhuǎn)發(fā)給另外的容器等孵,因為另外的容器是可用識別這個session的。)

另外可以使用sticky session failover機制來達到高擴展和高可用逞壁,不過這個現(xiàn)在不作討論流济。一般在web容器文檔可用找到如何實現(xiàn)session復制的配置锐锣。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末腌闯,一起剝皮案震驚了整個濱河市绳瘟,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌姿骏,老刑警劉巖糖声,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異分瘦,居然都是意外死亡蘸泻,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門嘲玫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來悦施,“玉大人,你說我怎么就攤上這事去团÷盏” “怎么了?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵土陪,是天一觀的道長昼汗。 經(jīng)常有香客問我,道長鬼雀,這世上最難降的妖魔是什么顷窒? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮源哩,結(jié)果婚禮上鞋吉,老公的妹妹穿的比我還像新娘。我一直安慰自己励烦,他們只是感情好谓着,可當我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著崩侠,像睡著了一般漆魔。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上却音,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天改抡,我揣著相機與錄音,去河邊找鬼系瓢。 笑死阿纤,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的夷陋。 我是一名探鬼主播欠拾,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼胰锌,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了藐窄?” 一聲冷哼從身側(cè)響起资昧,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎荆忍,沒想到半個月后格带,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡刹枉,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年叽唱,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片微宝。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡棺亭,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出蟋软,到底是詐尸還是另有隱情镶摘,我是刑警寧澤,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布钟鸵,位于F島的核電站钉稍,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏棺耍。R本人自食惡果不足惜贡未,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蒙袍。 院中可真熱鬧俊卤,春花似錦、人聲如沸害幅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽以现。三九已至狠怨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間邑遏,已是汗流浹背佣赖。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留记盒,地道東北人憎蛤。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親俩檬。 傳聞我的和親對象是個殘疾皇子萎胰,可洞房花燭夜當晚...
    茶點故事閱讀 45,512評論 2 359

推薦閱讀更多精彩內(nèi)容