前端面試:Cookie、Session和Token的工作原理是什麼?有什麼區別

前言

Web誕生之初,功能比較單一:允許Internet上任意一個用戶都可以從許多文檔服務計算機的數據庫中搜索和獲取文檔。服務器不需要記錄誰在某一段時間裡都瀏覽了什麼文檔,每次請求都是一個新的HTTP協議, 即請求加響應,

服務器不用記住是誰剛剛發了HTTP請求, 每個請求對服務器來說都是全新的。

隨著交互式Web應用的興起,網站有了登錄的需求,如在線購物網站,社交網站等等。這就面臨一個問題,服務器必須記住哪些人登錄了系統, 哪些人往自己的購物車中添加了商品, 也就是說服務器要識別每個用戶

因為HTTP請求是無狀態的,所以想出的辦法就是給大家發一個會話標識(session id), 說白了就是一個隨機的字串,每個用戶收到的都不一樣。 當用戶向服務器發起HTTP請求的時候,帶上這個字符串, 這樣服務器就能識別不同的用戶了。

所以就有了Session的引入,即服務端和客戶端都保存一段文本,客戶端每次發起請求都帶著,這樣服務器就知道客戶端是否發起過請求。

這樣,就導致客戶端頻繁向服務端發出請求數據,服務端頻繁的去數據庫查詢用戶名和密碼並進行對比,判斷用戶名和密碼正確與否。而Session的存儲是需要空間的,頻繁的查詢數據庫給服務器造成很大的壓力。

隨著Web移動端的興起,這種驗證的方式逐漸暴露出了問題。尤其是在可擴展性方面。

基於服務器驗證方式暴露的一些問題

1.Seesion:每次認證用戶發起請求時,服務器需要去創建一個記錄來存儲信息。當越來越多的用戶發請求時,內存的開銷也會不斷增加。

2.可擴展性:在服務端的內存中使用Seesion存儲登錄信息,伴隨而來的是可擴展性問題。

3.CORS(跨域資源共享):當我們需要讓數據跨多臺移動設備上使用時,跨域資源的共享會是一個讓人頭疼的問題。在使用Ajax抓取另一個域的資源,就可以會出現禁止請求的情況。

4.CSRF(跨站請求偽造):用戶在訪問銀行網站時,他們很容易受到跨站請求偽造的攻擊,並且能夠被利用其訪問其他的網站。

於是有人就一直在思考, 服務器為什麼要保存這些信息呢, 只讓每個客戶端去保存該多好?

在這種情況下,Token應用而生。

Token是服務端生成的一串字符串,以作客戶端進行請求的一個令牌。當客戶端第一次訪問服務端,服務端會根據傳過來的唯一標識userId,運用一些算法,並加上密鑰,生成一個Token,然後通過BASE64編碼一下之後將這個Token返回給客戶端,客戶端將Token保存起來(可以通過數據庫或文件形式保存本地)。下次請求時,客戶端只需要帶上Token,服務器收到請求後,會用相同的算法和密鑰

去驗證Token。

下圖,第一次時,獲得了“簽名”:

前端面試:Cookie、Session和Token的工作原理是什麼?有什麼區別

第二次或以後:服務器再次計算獲得新簽名,看看與客戶端帶過來簽名是否相等。(雖然帶過來的簽名也是服務器計算出來的)

前端面試:Cookie、Session和Token的工作原理是什麼?有什麼區別

Cookie

cookie 是一個非常具體的東西,指的就是瀏覽器裡面能永久存儲的一種數據,僅僅是瀏覽器實現的一種數據存儲功能。

cookie由服務器生成,發送給瀏覽器,瀏覽器把cookie以kv形式保存到某個目錄下的文本文件內,下一次請求同一網站時會把該cookie發送給服務器。由於cookie是存在客戶端上的,所以瀏覽器加入了一些限制確保cookie不會被惡意使用,同時不會佔據太多磁盤空間,所以每個域的cookie數量是有限的。

Cookie是客戶端保存用戶信息的一種機制,用來記錄用戶的一些信息,也是實現Session的一種方式。Cookie存儲的數據量有限,且都是保存在客戶端瀏覽器中。不同的瀏覽器有不同的存儲大小,但一般不超過4KB。因此使用Cookie實際上只能存儲一小段的文本信息。

例如:登錄網站,今輸入用戶名密碼登錄了,第二天再打開很多情況下就直接打開了。這個時候用到的一個機制就是Cookie。

Session

session 從字面上講,就是會話。這個就類似於你和一個人交談,你怎麼知道當前和你交談的是張三而不是李四呢?對方肯定有某種特徵(長相,口音等)表明他就是張三。

Session是另一種記錄客戶狀態的機制,它是在服務端保存的一個數據結構(主要存儲的SessionIDSession內容,同時也包含了很多自定義的內容如:用戶基礎信息、權限信息、用戶機構信息、固定變量等),這個數據可以保存在集群、數據庫、文件中,用於跟蹤用戶的狀態。

客戶端瀏覽器訪問服務器的時候,服務器把客戶端信息以某種形式記錄在服務器上。這就是Session。客戶端瀏覽器再次訪問時只需要從該Session中查找該客戶的狀態就可以了。

session 也是類似的道理,服務器要知道當前發請求給自己的是誰。為了做這種區分,服務器就要給每個客戶端分配不同的“

身份標識”,然後客戶端每次向服務器發請求的時候,都帶上這個“身份標識”,服務器就知道這個請求來自於誰了。至於客戶端怎麼保存這個“身份標識”,可以有很多種方式,對於瀏覽器客戶端,大家都默認採用 cookie 的方式。

服務器使用session把用戶的信息臨時保存在了服務器上,用戶離開網站後session會被銷燬。這種用戶信息存儲方式相對cookie來說更安全,可是session有一個缺陷:如果web服務器做了負載均衡,那麼下一個操作請求到了另一臺服務器的時候session會丟失。

用戶第一次登錄後,瀏覽器會將用戶信息發送給服務器,服務器會為該用戶創建一個SessionId,並在響應內容(Cookie)中將該SessionId一併返回給瀏覽器,瀏覽器將這些數據保存在本地。當用戶再次發送請求時,瀏覽器會自動的把上次請求存儲的Cookie數據自動的攜帶給服務器。

服務器接收到請求信息後,會通過瀏覽器請求的數據中的SessionId判斷當前是哪個用戶,然後根據SessionId在Session庫中獲取用戶的Session數據返回給瀏覽器。

例如:購物車,添加了商品之後客戶端處可以知道添加了哪些商品,而服務器端如何判別呢,所以也需要存儲一些信息就用到了Session。

Cookie和Session比較

如果說Cookie機制是通過檢查客戶身上的“通行證”來確定客戶身份的話,那麼Session機制就是通過檢查服務器上的“客戶明細表”來確認客戶身份。Session相當於程序在服務器上建立的一份客戶檔案,客戶來訪的時候只需要查詢客戶檔案表就可以了。

Session生成後,只要用戶繼續訪問,服務器就會更新Session的最後訪問時間,並維護該Session。為防止內存溢出,服務器會把長時間內沒有活躍的Session從內存刪除。這個時間就是Session的超時時間。如果超過了超時時間沒訪問過服務器,Session就自動失效了。

Token

Web領域基於Token的身份驗證隨處可見。在大多數使用Web API的互聯網公司中,tokens 是多用戶下處理認證的最佳方式。

大部分你見到過的API和Web應用都使用tokens。例如Facebook, Twitter, Google+, GitHub等。

最簡單的Token組成:uid(用戶唯一的身份標識)、time(當前時間的時間戳)、sign(簽名,由Token的前幾位+鹽以哈希算法壓縮成一定長的十六進制字符串,可以防止惡意第三方拼接Token請求服務器)

基於Token的驗證原理

基於Token的身份驗證是無狀態的,我們不將用戶信息存在服務器或Session中。

這種概念解決了在服務端存儲信息時的許多問題,NoSession意味著你的程序可以根據需要去增減機器,而不用去擔心用戶是否登錄。

使用基於 Token 的身份驗證方法,在服務端不需要存儲用戶的登錄記錄。大概的流程是這樣的:

  • 客戶端使用用戶名跟密碼請求登錄
  • 服務端收到請求,去驗證用戶名與密碼
  • 驗證成功後,服務端會簽發一個 Token,再把這個 Token 發送給客戶端
  • 客戶端收到 Token 以後可以把它存儲起來,比如放在 Cookie 裡或者數據庫裡
  • 客戶端每次向服務端請求資源的時候需要帶著服務端簽發的 Token
  • 服務端收到請求,然後去驗證客戶端請求裡面帶著的 Token,如果驗證成功,就向客戶端返回請求的數據

每一次請求都需要token。token應該在HTTP的頭部發送從而保證了Http請求無狀態。我們同樣通過設置服務器屬性Access-Control-Allow-Origin:* ,讓服務器能接受到來自所有域的請求。需要注意的是,在ACAO頭部標明(designating)*時,不得帶有像HTTP認證,客戶端SSL證書和cookies的證書。

實現思路:

前端面試:Cookie、Session和Token的工作原理是什麼?有什麼區別

Tokens的優勢

1.無狀態、可擴展

在客戶端存儲的Tokens是無狀態的,並且能夠被擴展。基於這種無狀態和不存儲Session信息,負載負載均衡器能夠將用戶信息從一個服務傳到其他服務器上。

如果我們將已驗證的用戶的信息保存在Session中,則每次請求都需要用戶向已驗證的服務器發送驗證信息(稱為Session親和性)。用戶量大時,可能會造成一些擁堵。但是不要著急。使用tokens之後這些問題都迎刃而解,因為tokens自己hold住了用戶的驗證信息。

2.安全性

請求中發送token而不再是發送cookie,能夠防止CSRF(跨站請求偽造)。即使在客戶端使用cookie存儲token,cookie也僅僅是一個存儲機制而不是用於認證。不將信息存儲在Session中,讓我們少了對session操作。

token是有時效的,一段時間之後用戶需要重新驗證。我們也不一定需要等到token自動失效,token有撤回的操作,通過token revocataion可以使一個特定的token或是一組有相同認證的token無效。

3.可擴展性

Tokens能夠創建與其它程序共享權限的程序。例如,能將一個隨便的社交帳號和自己的大號(Fackbook或是Twitter)聯繫起來。當通過服務登錄Twitter(我們將這個過程Buffer)時,我們可以將這些Buffer附到Twitter的數據流上(we are allowing Buffer to post to our Twitter stream)。使用tokens時,可以提供可選的權限給第三方應用程序。當用戶想讓另一個應用程序訪問它們的數據,我們可以通過建立自己的API,得出特殊權限的tokens。

4.多平臺跨域

我們提前先來談論一下CORS(跨域資源共享),對應用程序和服務進行擴展的時候,需要介入各種各種的設備和應用程序。

只要用戶有一個通過了驗證的token,數據和資源就能夠在任何域上被請求到。

 Access-Control-Allow-Origin: * 

App示例:

APP登錄的時候發送加密的用戶名和密碼到服務器,服務器驗證用戶名和密碼,如果成功,以某種方式比如隨機生成32位的字符串作為Token,存儲到服務器中,並返回Token到APP,以後APP請求時,凡是需要驗證的地方都要帶上該Token,然後服務器端驗證Token,成功返回所需要的結果,失敗返回錯誤信息,讓他重新登錄。

對於同一個APP同一個手機當前只有一個Token;手機APP會存儲一個當前有效的Token。其中服務器上Token設置一個有效期,每次APP請求的時候都驗證Token和有效期。


分享到:


相關文章: