簡單-3種 web 會話管理的方式

http是無狀態(tài)的,一次請求結(jié)束,連接斷開,下次服務(wù)器再收到請求,它就不知道這個請求是哪個用戶發(fā)過來的。當(dāng)然它知道是哪個客戶端地址發(fā)過來的,但是對于我們的應(yīng)用來說,我們是靠用戶來管理,而不是靠客戶端。所以對我們的應(yīng)用而言,它是需要有狀態(tài)管理的,以便服務(wù)端能夠準(zhǔn)確的知道http請求是哪個用戶發(fā)起的,從而判斷他是否有權(quán)限繼續(xù)這個請求。這個過程就是常說的會話管理。它也可以簡單理解為一個用戶從登錄到退出應(yīng)用的一段期間。本文總結(jié)了3種常見的實現(xiàn)web應(yīng)用會話管理的方式:
1)基于server端session的管理方式
2)cookie-base的管理方式
3)token-base的管理方式
這些內(nèi)容可以幫助加深對web中用戶登錄機制的理解,對實際項目開發(fā)也有參考價值,歡迎閱讀與指正。

1. 基于server端session的管理
在早期web應(yīng)用中,通常使用服務(wù)端session來管理用戶的會話。快速了解服務(wù)端session:

  1. 服務(wù)端session是用戶第一次訪問應(yīng)用時,服務(wù)器就會創(chuàng)建的對象,代表用戶的一次會話過程,可以用來存放數(shù)據(jù)。服務(wù)器為每一個session都分配一個唯一的sessionid,以保證每個用戶都有一個不同的session對象。
    2)服務(wù)器在創(chuàng)建完session后,會把sessionid通過cookie返回給用戶所在的瀏覽器,這樣當(dāng)用戶第二次及以后向服務(wù)器發(fā)送請求的時候,就會通過cookie把sessionid傳回給服務(wù)器,以便服務(wù)器能夠根據(jù)sessionid找到與該用戶對應(yīng)的session對象。
    3)session通常有失效時間的設(shè)定,比如2個小時。當(dāng)失效時間到,服務(wù)器會銷毀之前的session,并創(chuàng)建新的session返回給用戶。但是只要用戶在失效時間內(nèi),有發(fā)送新的請求給服務(wù)器,通常服務(wù)器都會把他對應(yīng)的session的失效時間根據(jù)當(dāng)前的請求時間再延長2個小時。
    4)session在一開始并不具備會話管理的作用。它只有在用戶登錄認證成功之后,并且往sesssion對象里面放入了用戶登錄成功的憑證,才能用來管理會話。管理會話的邏輯也很簡單,只要拿到用戶的session對象,看它里面有沒有登錄成功的憑證,就能判斷這個用戶是否已經(jīng)登錄。當(dāng)用戶主動退出的時候,會把它的session對象里的登錄憑證清掉。所以在用戶登錄前或退出后或者session對象失效時,肯定都是拿不到需要的登錄憑證的。

    以上過程可簡單使用流程圖描述如下:

    主流的web開發(fā)平臺(java,.net,php)都原生支持這種會話管理的方式,而且開發(fā)起來很簡單,相信大部分后端開發(fā)人員在入門的時候都了解并使用過它。它還有一個比較大的優(yōu)點就是安全性好,因為在瀏覽器端與服務(wù)器端保持會話狀態(tài)的媒介始終只是一個sessionid串,只要這個串夠隨機,攻擊者就不能輕易冒充他人的sessionid進行操作;除非通過CSRF或http劫持的方式,才有可能冒充別人進行操作;即使冒充成功,也必須被冒充的用戶session里面包含有效的登錄憑證才行。但是在真正決定用它管理會話之前,也得根據(jù)自己的應(yīng)用情況考慮以下幾個問題:
    1)這種方式將會話信息存儲在web服務(wù)器里面,所以在用戶同時在線量比較多時,這些會話信息會占據(jù)比較多的內(nèi)存;
    2)當(dāng)應(yīng)用采用集群部署的時候,會遇到多臺web服務(wù)器之間如何做session共享的問題。因為session是由單個服務(wù)器創(chuàng)建的,但是處理用戶請求的服務(wù)器不一定是那個創(chuàng)建session的服務(wù)器,這樣他就拿不到之前已經(jīng)放入到session中的登錄憑證之類的信息了;
    3)多個應(yīng)用要共享session時,除了以上問題,還會遇到跨域問題,因為不同的應(yīng)用可能部署的主機不一樣,需要在各個應(yīng)用做好cookie跨域的處理。

    針對問題1和問題2,我見過的解決方案是采用redis這種中間服務(wù)器來管理session的增刪改查,一來減輕web服務(wù)器的負擔(dān),二來解決不同web服務(wù)器共享session的問題。針對問題3,由于服務(wù)端的session依賴cookie來傳遞sessionid,所以在實際項目中,只要解決各個項目里面如何實現(xiàn)sessionid的cookie跨域訪問即可,這個是可以實現(xiàn)的,就是比較麻煩,前后端有可能都要做處理。
    如果不考慮以上三個問題,這種管理方式比較值得使用,尤其是一些小型的web應(yīng)用。但是一旦應(yīng)用將來有擴展的必要,那就得謹(jǐn)慎對待前面的三個問題。如果真要在項目中使用這種方式,推薦結(jié)合單點登錄框架如CAS一起用,這樣會使應(yīng)用的擴展性更強。

2. cookie-based的管理方式

由于前一種方式會增加服務(wù)器的負擔(dān)和架構(gòu)的復(fù)雜性,所以后來就有人想出直接把用戶的登錄憑證直接存到客戶端的方案,當(dāng)用戶登錄成功之后,把登錄憑證寫到cookie里面,并給cookie設(shè)置有效期,后續(xù)請求直接驗證存有登錄憑證的cookie是否存在以及憑證是否有效,即可判斷用戶的登錄狀態(tài)。使用它來實現(xiàn)會話管理的整體流程如下:
1)用戶發(fā)起登錄請求,服務(wù)端根據(jù)傳入的用戶密碼之類的身份信息,驗證用戶是否滿足登錄條件,如果滿足,就根據(jù)用戶信息創(chuàng)建一個登錄憑證,這個登錄憑證簡單來說就是一個對象,最簡單的形式可以只包含用戶id,憑證創(chuàng)建時間和過期時間三個值。
2)服務(wù)端把上一步創(chuàng)建好的登錄憑證,先對它做數(shù)字簽名,然后再用對稱加密算法做加密處理,將簽名、加密后的字串,寫入cookie。cookie的名字必須固定(如ticket),因為后面再獲取的時候,還得根據(jù)這個名字來獲取cookie值。這一步添加數(shù)字簽名的目的是防止登錄憑證里的信息被篡改,因為一旦信息被篡改,那么下一步做簽名驗證的時候肯定會失敗。做加密的目的,是防止cookie被別人截取的時候,無法輕易讀到其中的用戶信息。
3)用戶登錄后發(fā)起后續(xù)請求,服務(wù)端根據(jù)上一步存登錄憑證的cookie名字,獲取到相關(guān)的cookie值。然后先做解密處理,再做數(shù)字簽名的認證,如果這兩步都失敗,說明這個登錄憑證非法;如果這兩步成功,接著就可以拿到原始存入的登錄憑證了。然后用這個憑證的過期時間和當(dāng)前時間做對比,判斷憑證是否過期,如果過期,就需要用戶再重新登錄;如果未過期,則允許請求繼續(xù)。


這種方式最大的優(yōu)點就是實現(xiàn)了服務(wù)端的無狀態(tài)化,徹底移除了服務(wù)端對會話的管理的邏輯,服務(wù)端只需要負責(zé)創(chuàng)建和驗證登錄cookie即可,無需保持用戶的狀態(tài)信息。對于第一種方式的第二個問題,用戶會話信息共享的問題,它也能很好解決:因為如果只是同一個應(yīng)用做集群部署,由于驗證登錄憑證的代碼都是一樣的,所以不管是哪個服務(wù)器處理用戶請求,總能拿到cookie中的登錄憑證來進行驗證;如果是不同的應(yīng)用,只要每個應(yīng)用都包含相同的登錄邏輯,那么他們也是能輕易實現(xiàn)會話共享的,不過這種情況下,登錄邏輯里面數(shù)字簽名以及加密解密要用到的密鑰文件或者密鑰串,需要在不同的應(yīng)用里面共享,總而言之,就是需要算法完全保持一致。
這種方式由于把登錄憑證直接存放客戶端,并且需要cookie傳來傳去,所以它的缺點也比較明顯:
1)cookie有大小限制,存儲不了太多數(shù)據(jù),所以要是登錄憑證存的消息過多,導(dǎo)致加密簽名后的串太長,就會引發(fā)別的問題,比如其它業(yè)務(wù)場景需要cookie的時候,就有可能沒那么多空間可用了;所以用的時候得謹(jǐn)慎,得觀察實際的登錄cookie的大小;比如太長,就要考慮是非是數(shù)字簽名的算法太嚴(yán)格,導(dǎo)致簽名后的串太長,那就適當(dāng)調(diào)整簽名邏輯;比如如果一開始用4096位的RSA算法做數(shù)字簽名,可以考慮換成1024、2048位;
2)每次傳送cookie,增加了請求的數(shù)量,對訪問性能也有影響;
3)也有跨域問題,畢竟還是要用cookie。
相比起第一種方式,cookie-based方案明顯還是要好一些,目前好多web開發(fā)平臺或框架都默認使用這種方式來做會話管理,比如php里面yii框架,這是我們團隊后端目前用的,它用的就是這個方案,以上提到的那些登錄邏輯,框架也都已經(jīng)封裝好了,實際用起來也很簡單;asp.net里面forms身份認證,也是這個思路,這里有一篇好文章把它的實現(xiàn)細節(jié)都說的很清楚:
http://www.cnblogs.com/fish-li/archive/2012/04/15/2450571.html
前面兩種會話管理方式因為都用到cookie,不適合用在native app里面:native app不好管理cookie,畢竟它不是瀏覽器。這兩種方案都不適合用來做純api服務(wù)的登錄認證。要實現(xiàn)api服務(wù)的登錄認證,就要考慮下面要介紹的第三種會話管理方式。

3. token-based的管理方式

這種方式從流程和實現(xiàn)上來說,跟cookie-based的方式?jīng)]有太多區(qū)別,只不過cookie-based里面寫到cookie里面的ticket在這種方式下稱為token,這個token在返回給客戶端之后,后續(xù)請求都必須通過url參數(shù)或者是http header的形式,主動帶上token,這樣服務(wù)端接收到請求之后就能直接從http header或者url里面取到token進行驗證:



這種方式不通過cookie進行token的傳遞,而是每次請求的時候,主動把token加到http header里面或者url后面,所以即使在native app里面也能使用它來調(diào)用我們通過web發(fā)布的api接口。app里面還要做兩件事情:
1)有效存儲token,得保證每次調(diào)接口的時候都能從同一個位置拿到同一個token;
2)每次調(diào)接口的的代碼里都得把token加到header或者接口地址里面。
看起來麻煩,其實也不麻煩,這兩件事情,對于app來說,很容易做到,只要對接口調(diào)用的模塊稍加封裝即可。
這種方式同樣適用于網(wǎng)頁應(yīng)用,token可以存于localStorage或者sessionStorage里面,然后每發(fā)ajax請求的時候,都把token拿出來放到ajax請求的header里即可。不過如果是非接口的請求,比如直接通過點擊鏈接請求一個頁面這種,是無法自動帶上token的。所以這種方式也僅限于走純接口的web應(yīng)用。
這種方式用在web應(yīng)用里也有跨域的問題,比如應(yīng)用如果部署在a.com,api服務(wù)部署在b.com,從a.com里面發(fā)出ajax請求到b.com,默認情況下是會報跨域錯誤的,這種問題可以用CORS(跨域資源共享)的方式來快速解決,相關(guān)細節(jié)可去閱讀前面給出的CORS文章詳細了解。
這種方式跟cookie-based的方式同樣都還有的一個問題就是ticket或者token刷新的問題。有的產(chǎn)品里面,你肯定不希望用戶登錄后,操作了半個小時,結(jié)果ticket或者token到了過期時間,然后用戶又得去重新登錄的情況出現(xiàn)。這個時候就得考慮ticket或token的自動刷新的問題,簡單來說,可以在驗證ticket或token有效之后,自動把ticket或token的失效時間延長,然后把它再返回給客戶端;客戶端如果檢測到服務(wù)器有返回新的ticket或token,就替換原來的ticket或token。

4. 安全問題

在web應(yīng)用里面,會話管理的安全性始終是最重要的安全問題,這個對用戶的影響極大。
首先從會話管理憑證來說,第一種方式的會話憑證僅僅是一個session id,所以只要這個session id足夠隨機,而不是一個自增的數(shù)字id值,那么其它人就不可能輕易地冒充別人的session id進行操作;第二種方式的憑證(ticket)以及第三種方式的憑證(token)都是一個在服務(wù)端做了數(shù)字簽名,和加密處理的串,所以只要密鑰不泄露,別人也無法輕易地拿到這個串中的有效信息并對它進行篡改。總之,這三種會話管理方式的憑證本身是比較安全的。
然后從客戶端和服務(wù)端的http過程來說,當(dāng)別人截獲到客戶端請求中的會話憑證,就能拿這個憑證冒充原用戶,做一些非法操作,而服務(wù)器也認不出來。這種安全問題,可以簡單采用https來解決,雖然可能還有http劫持這種更高程度的威脅存在,但是我們從代碼能做的防范,確實也就是這個層次了。
最后的安全問題就是CSRF(跨站請求偽造)。這個跟代碼有很大關(guān)系,本質(zhì)上它就是代碼的漏洞,只不過一般情況下這些漏洞,作為開發(fā)人員都不容易發(fā)現(xiàn),只有那些一門心思想搞些事情的人才會專門去找這些漏洞,所以這種問題的防范更多地還是依賴于開發(fā)人員對這種攻擊方式的了解,包括常見的攻擊形式和應(yīng)對方法。不管憑證信息本身多么安全,別人利用CSRF,就能拿到別人的憑證,然后用它冒充別人進行非法操作,所以有時間還真得多去了解下它的相關(guān)資料才行。舉例來說,假如我們把憑證直接放到url后面進行傳遞,就有可能成為一個CSRF的漏洞:當(dāng)惡意用戶在我們的應(yīng)用內(nèi)上傳了1張引用了他自己網(wǎng)站的圖片,當(dāng)正常的用戶登錄之后訪問的頁面里面包含這個圖片的時候,由于這個圖片加載的時候會向惡意網(wǎng)站發(fā)送get請求;當(dāng)惡意網(wǎng)站收到請求的時候,就會從這個請求的Reffer header里面看到包含這個圖片的頁面地址,而這個地址正好包含了正常用戶的會話憑證;于是惡意用戶就拿到了正常用戶的憑證;只要這個憑證還沒失效,他就能用它冒充用戶進行非法操作。

5. 總結(jié)
前面這三種方式,各自有各自的優(yōu)點及使用場景,我覺得沒有哪個是最好的,做項目的時候,根據(jù)項目將來的擴展情況和架構(gòu)情況,才能決定用哪個是最合適的。本文的目的也就是想介紹這幾種方式的原理,以便掌握web應(yīng)用中登錄驗證的關(guān)鍵因素。
作為一個前端開發(fā)人員,本文雖然介紹了3種會話管理的方式,但是與前端關(guān)系最緊密的還是第三種方式,畢竟現(xiàn)在前端開發(fā)SPA應(yīng)用以及hybrid應(yīng)用已經(jīng)非常流行了,所以掌握好這個方式的認證過程和使用方式,對前端來說,顯然是很有幫助的。好在這個方式的技術(shù)其實早就有很多實現(xiàn)了,而且還有現(xiàn)成的標(biāo)準(zhǔn)可用,這個標(biāo)準(zhǔn)就是JWT(json-web-token)。
JWT本身并沒有做任何技術(shù)實現(xiàn),它只是定義了token-based的管理方式該如何實現(xiàn),它規(guī)定了token的應(yīng)該包含的標(biāo)準(zhǔn)內(nèi)容以及token的生成過程和方法。目前實現(xiàn)了這個標(biāo)準(zhǔn)的技術(shù)已經(jīng)有非常多:


更多可參閱:https://jwt.io/#libraries-io
為了對第三種會話管理方式的實現(xiàn)有個更全面的認識,我選擇用express和上面眾多JWT實現(xiàn)中的jsonwebtoken來研究,相關(guān)內(nèi)容我會在下一篇博客詳細介紹。本文內(nèi)容到此結(jié)束,謝謝閱讀,歡迎關(guān)注下一篇博客的內(nèi)容。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,606評論 6 533
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 98,582評論 3 418
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,540評論 0 376
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,028評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 71,801評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,223評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,294評論 3 442
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,442評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 48,976評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 40,800評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,996評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,543評論 5 360
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 44,233評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,662評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,926評論 1 286
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,702評論 3 392
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 47,991評論 2 374

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