首頁  >  文章  >  你還傻傻分不清Cookie、Session、Token、JWT嗎?

你還傻傻分不清Cookie、Session、Token、JWT嗎?

coldplay.xixi
coldplay.xixi轉載
2020-08-19 12:01:295861瀏覽

你還傻傻分不清Cookie、Session、Token、JWT嗎?

什麼是認證(Authentication)

  • 通俗地講就是驗證當前用戶的身份,證明“你是你自己” (例如:你每天上下班打卡,都需要通過指紋打卡,當你的指紋和系統裡錄入的指紋相匹配時,就打卡成功)
  • 互聯網中的認證:
    • #使用者名稱密碼登入
    • 郵件傳送登入連結
    • 手機號碼接收驗證碼
    • #只要能收到信箱/驗證碼,就預設你是帳號的主人

什麼是授權(Authorization)

  • #使用者授予第三方應用程式存取該使用者某些資源的權限
    • 你在安裝手機應用程式的時候,APP 會詢問是否允許授予權限(存取相簿、地理位置等權限)
    • 你在存取微信小程式時,當登入時,小程式會詢問是否允許授予權限(取得暱稱、個人資料、地區、性別等個人資訊)
  • 實現授權的方式有:cookie、session、token、OAuth

  • #什麼是憑證(Credentials)
  • 實現認證和授權的前提是需要一種媒介(憑證)
  • 來標記訪客的身分
  • 在戰國時期,商鞅變法,發明了照身帖。照身帖由官府發放,是一塊打磨光滑細密的竹板,上面刻有持有者的頭像和籍貫訊息。國人必須持有,如若沒有就被認為是黑戶,或間諜之類的。 在現實生活中,每個人都會有一張專屬的居民身分證,是用來證明持有人身分的一種法定證件。透過身分證,我們可以辦理手機卡/銀行卡/個人貸款/交通出行等等,這就是認證的憑證。
  • 在網路應用程式中,一般網站(如掘金)會有兩種模式,遊客模式和登入模式。遊客模式下,可以正常瀏覽網站上面的文章,一旦想要按讚/收藏/分享文章,就需要登入或註冊帳號。當使用者登入成功後,伺服器會給該使用者使用的瀏覽器頒發一個令牌(token),這個令牌用來表明你的身份,每次瀏覽器發送請求時會帶上這個令牌,就可以使用遊客模式下無法使用的功能。

什麼是Cookie#############HTTP 是無狀態的協定(對於交易處理沒有記憶能力,每次客戶端和服務當端會話完成時,服務端不會保存任何會話訊息###):每個請求都是完全獨立的,服務端無法確認目前訪客的身份訊息,無法分辨上一次的請求發送者和這次的發送者是不是同一個人。所以伺服器與瀏覽器為了進行會話追蹤(知道是誰在訪問我),就必須主動的去維護一個狀態,這個狀態用於告知服務端前後兩個請求是否來自同一瀏覽器。而這個狀態需要透過 cookie 或 session 去實現。 #########cookie 儲存在客戶端:### cookie 是伺服器發送到使用者瀏覽器並保存在本地的一小塊數據,它會在瀏覽器下次向同一伺服器重新發起請求時被攜帶並發送到伺服器上。 #########cookie 是不可跨域的:### 每個cookie 都會綁定單一的域名,無法在別的域名下取得使用,###一級域名和二級域名之間是允許共享使用的###(###靠的是domain)###。 ############cookie 重要的屬性#######
屬性 說明
name=value #鍵值對,設定Cookie 的名稱及相對應的值,都必須是字串類型
- 如果值為Unicode 字符,需要為字符編碼。
- 如果值為二進位數據,則需要使用 BASE64 編碼。
domain 指定cookie 所屬域名,預設是目前域名
path 指定cookie 在哪個路徑(路由)下生效,預設為'/'
如果設定為 /abc,則只有 /abc 下的路由可以存取到該 cookie,如:/abc/read
maxAge cookie 失效的時間,單位秒。如果為整數,則該 cookie 在 maxAge 秒後失效。若為負數,則該 cookie 為暫存 cookie ,關閉瀏覽器即失效,瀏覽器也不會以任何形式儲存該 cookie 。如果為 0,表示刪除該 cookie 。預設為 -1。
- 比 expires 好用
expires 過期時間,在設定的某個時間點後該 cookie 就會失效。
一般瀏覽器的cookie 都是預設儲存的,當關閉瀏覽器結束這個會話的時候,這個cookie 也會被刪除
secure 該cookie 是否僅被使用安全協定傳輸。安全協定有 HTTPS,SSL等,在網路上傳輸資料前先將資料加密。預設為false。
當 secure 值為 true 時,cookie 在 HTTP 中是無效,在 HTTPS 中才有效。
httpOnly 如果給某個cookie 設定了httpOnly 屬性,則無法透過JS 腳本讀取到該cookie 的訊息,但還是能透過Application 中手動修改cookie,所以只是在一定程度上可以防止XSS 攻擊,不是絕對的安全性


#

相關專題推薦:php cookie(專題)

#什麼是Session

  • session 是另一種記錄伺服器和客戶端會話狀態的機制
  • session 是基於cookie 實作的,session 儲存在伺服器端,sessionId 會被儲存到客戶端的cookie 中
你還傻傻分不清Cookie、Session、Token、JWT嗎?
  • session 認證流程:
    • 用戶第一次請求伺服器的時候,伺服器根據用戶提交的相關信息,建立對應的Session
    • 請求返回時將此Session 的唯一識別資訊SessionID 傳回給瀏覽器
    • 瀏覽器接收到伺服器傳回的SessionID 資訊後,會將此資訊存入到Cookie中,同時Cookie 記錄此SessionID 屬於哪個域名
    • 當用戶第二次訪問伺服器的時候,請求會自動判斷此域名下是否存在Cookie 訊息,如果存在自動將Cookie 訊息也發送給服務端,服務端會從Cookie 中取得SessionID,再根據SessionID 尋找對應的Session 訊息,如果沒有找到說明使用者沒有登入或登入失效,如果找到Session 證明使用者已經登入可執行後面操作。

根據上述流程可知,SessionID 是連接 Cookie 和 Session 的一道橋樑,大部分系統也是根據此原理來驗證使用者登入狀態。

相關專題推薦:php session 會話(專題)

#

Cookie 和 Session 的區別

  • 安全性: Session 比 Cookie 安全,Session 是儲存在伺服器端的,Cookie 是儲存在客戶端的。
  • 存取值的類型不同:Cookie 只支援存字串數據,想要設定其他類型的數據,需要將其轉換成字串,Session 可以存任意資料類型。
  • 有效期限不同: Cookie 可設定為長時間維持,例如我們經常使用的預設登入功能,Session 一般失效時間較短,客戶端關閉(預設)或Session 逾時都會失效。
  • 儲存大小不同: 單一 Cookie 儲存的資料不能超過 4K,Session 可儲存資料遠高於 Cookie,但是當存取量過多,會佔用過多的伺服器資源。

什麼是Token(令牌)

Acesss Token

  • 訪問資源介面(API)時所需要的資源憑證
  • 簡單token 的組成: uid(用戶唯一的識別)、time(當前時間的時間戳)、sign(簽名,token 的前幾位以哈希演算法壓縮成的一定長度的十六進位字串)
  • 特點:
    • #服務端無狀態化、可擴展性好
    • #支援行動端裝置
    • 安全性
    • 支援跨程式呼叫
  • ##token 的身份驗證流程:
你還傻傻分不清Cookie、Session、Token、JWT嗎?
    客戶端使用使用者名稱跟密碼請求登入
  1. 服務端收到請求,去驗證用戶名與密碼
  2. 驗證成功後,服務端會簽發一個token 並把這個token 發送給客戶端
  3. 客戶端收到token 以後,會把它儲存起來,例如放在cookie里或者localStorage 裡
  4. 客戶端每次向服務端請求資源的時候需要帶著服務端簽發的token
  5. 服務端收到請求,然後去驗證客戶端請求裡面帶著的token ,如果驗證成功,就向客戶端回傳請求的資料
  • #每個要求都需要攜帶token,需要把token 放到HTTP 的Header 裡
  • 基於token 的使用者認證是一種服務端無狀態的認證方式,服務端不用存放token 資料。用解析token 的計算時間換取session 的儲存空間,從而減輕伺服器的壓力,減少頻繁的查詢資料庫
  • token 完全由應用程式管理,所以它可以避開同源策略
Refresh Token

    另外一種token——refresh token
  • refresh token 是專用於刷新 access token 的 token。如果沒有 refresh token,也可以刷新 access token,但每次刷新都要用戶輸入登入使用者名稱與密碼,會很麻煩。有了 refresh token,可以減少這個麻煩,客戶端直接用 refresh token 去更新 access token,無需用戶進行額外的操作。
你還傻傻分不清Cookie、Session、Token、JWT嗎?
  • Access Token 的有效期限比較短,當Acesss Token 因過期而失效時,使用Refresh Token 就可以獲得新的Token,如果Refresh Token 也失效了,用戶就只能重新登入了。
  • Refresh Token 及過期時間是儲存在伺服器的資料庫中,只有在申請新的Acesss Token 時才會驗證,不會對業務介面回應時間造成影響,也不需要向Session 一樣一直保持在內存中以應對大量的請求。

Token 和Session 的區別

  • Session 是一種記錄伺服器和客戶端會話狀態的機制,使服務端有狀態化,可以記錄會話資訊.而 Token 是令牌存取資源介面(API)時所需要的資源憑證。 Token 使服務端無狀態化,不會儲存會話資訊。
  • Session 和Token 並不矛盾,作為身分認證Token 安全性比Session 好,因為每個請求都有簽章還能防止監聽以及重播攻擊,而Session 就必須依賴連結層來保障通訊安全了。 如果你需要實作有狀態的會話,仍然可以增加 Session 來在伺服器端保存一些狀態。
  • 所謂 Session 認證只是簡單的把 User 資訊儲存到 Session 裡,因為 SessionID 的不可預測性,暫且認為是安全的。而 Token ,如果指的是 OAuth Token 或類似的機制的話,提供的是 認證 和 授權 ,認證是針對用戶,授權是針對 App 。其目的是讓某 App 有權利存取某使用者的資訊。這裡的 Token 是唯一的。不可以轉移到其它 App上,也不可以轉到其它用戶上。 Session 只提供一種簡單的認證,即只要有此 SessionID ,即認為有此 User 的全部權利。是需要嚴格保密的,這個資料應該只保存在站方,不應該分享給其它網站或第三方 App。所以簡單來說:如果你的用戶資料可能需要和第三方共享,或者允許第三方調用 API 接口,用 Token 。如果永遠只是自己的網站,自己的 App,用什麼就無所謂了。

什麼是 JWT

  • JSON Web Token(簡稱 JWT)是目前最受歡迎的跨域認證解決方案。
  • 是一種認證授權機制
  • JWT 是為了在網路應用環境間傳遞宣告而執行的一種基於 JSON 的開放標準(RFC 7519)。 JWT 的聲明一般被用來在身分提供者和服務提供者間傳遞已認證的使用者身分訊息,以便於從資源伺服器取得資源。例如用在用戶登入。
  • 可以使用 HMAC 演算法或是 RSA 的公/私秘鑰對 JWT 進行簽署。因為數位簽章的存在,這些傳遞的訊息是可信的。
  • 阮一峰老師的JSON Web Token 入門教程講的非常通俗易懂,這裡就不再班門弄斧了

生成JWT

#jwt.io/
www.jsonwebtoken.io/

#

JWT 的原理

你還傻傻分不清Cookie、Session、Token、JWT嗎?
  • JWT 認證流程:
    • 使用者輸入使用者名稱/密碼登錄,服務端認證成功後,會傳回給客戶端一個JWT
    • 客戶端將token 儲存到本地(通常使用localstorage,也可以使用cookie)
    • 當使用者希望存取一個受保護的路由或者資源的時候,需要請求頭的Authorization 欄位中使用Bearer 模式新增JWT,其內容看起來是下面這樣
Authorization: Bearer <token>复制代码</token>
  • 服務端的保護路由將會檢查請求頭Authorization 中的JWT 信息,如果合法,則允許用戶的行為
  • 因為JWT 是自包含的(內部包含了一些會話信息),因此減少了需要查詢數據庫的需要
  • 因為JWT 並沒有使用Cookie 的,所以你可以使用任何網域提供你的API 服務而不需要擔心跨網域資源共享問題(CORS)
  • 因為使用者的狀態不再儲存在服務端的記憶體中,所以這是一種無狀態的認證機制

JWT 的使用方式

  • 客戶端收到伺服器傳回的JWT,可以儲存在Cookie 裡面,也可以儲存在localStorage。
  • 當使用者希望存取受保護的路由或資源的時候,可以把它放在Cookie 裡面自動發送,但是這樣不能跨域,所以更好的做法是放在HTTP 請求頭訊息的Authorization 欄位裡,使用Bearer 模式加入JWT。

    GET /calendar/v1/events
    Host: api.example.com
    Authorization: Bearer <token>复制代码</token>
    • 使用者的狀態不會儲存在服務端的記憶體中,這是一種無狀態的認證機制
    • 服務端的保護路由將會檢查請求頭Authorization 中的JWT 訊息,如果合法,則允許使用者的行為。
    • 由於JWT 是自包含的,因此減少了需要查詢資料庫的需要
    • JWT 的這些特性使得我們可以完全依賴其無狀態的特性提供資料API 服務,甚至是建立一個下載串流服務。
    • 因為JWT 不使用Cookie ,所以你可以使用任何網域提供你的API 服務而不需要擔心跨網域資源共享問題(CORS)

方式二

  • 跨域的時候,可以把JWT 放在POST 請求的資料體裡。

方式三

  • 透過URL 傳送
http://www.example.com/user?token=xxx复制代码

專案中使用JWT

專案位址

Token 和JWT 的差異

相同:

  • 都是存取資源的令牌
  • 都可以記錄使用者的資訊
  • 都是讓服務端無狀態化
  • 都是只有驗證成功後,客戶端才能存取服務端上受保護的資源

區別:

#
  • Token:服務端驗證客戶端發送過來的 Token 時,還需要查詢資料庫取得使用者信息,然後驗證 Token 是否有效。
  • JWT: 將Token 和Payload 加密後儲存於客戶端,服務端只需要使用金鑰解密進行校驗(校驗也是JWT 自己實現的)即可,不需要查詢或減少查詢資料庫,因為JWT 自包含了用戶資訊和加密的資料。

常見的前後端鑑權方式

  1. Session-Cookie
  2. Token 驗證(包括JWT,SSO)
  3. OAuth2.0(開放授權)

#常見的加密演算法

你還傻傻分不清Cookie、Session、Token、JWT嗎?
  • 哈希演算法(Hash Algorithm)又稱雜湊演算法、雜湊函數、雜湊函數,是一種從任何一種資料中創建小的數字“指紋”的方法。哈希演算法將資料重新打亂混合,重新建立一個哈希值。
  • 雜湊演算法主要用來保障資料真實性(即完整性),即發信人將原始訊息和雜湊值一起傳送,收信人透過相同的雜湊函數來校驗原始資料是否真實。
  • 雜湊演算法通常有以下幾個特點:
    • 正像快速:原始資料可以快速計算出雜湊值
    • 逆向困難:透過雜湊值基本上不可能推導出原始資料
    • 輸入敏感:原始資料只要有一點變動,得到的雜湊值差異很大
    • 衝突避免:很難找到不同的原始資料得到相同的雜湊值,宇宙中原子數大約在10 的60 次方到80 次方之間,所以2 的256 次方有足夠的空間容納所有的可能,演算法好的情況下衝突碰撞的機率很低:
      • 2 的128 次方為340282366920938463463374607431768211456,也就是10 的39 次方等級
      • 2 的160 次方為1.46150163730
      • #282036838236223838320383832038級別
      • 2的256 次方為1.1579208923731619542357098500869 × 10 的77 次方,也就是10 的77 次方

#。篡改,原始資料和雜湊值都可能被惡意篡改,要保證不被篡改,可以使用RSA 公鑰私鑰方案,再配合雜湊值。

    雜湊演算法主要用來防止電腦傳輸過程中的錯誤,早期電腦透過前7 位元資料第8 位元奇偶校驗碼來保障(12.5% 的浪費效率低),對於一段資料或文件,透過哈希演算法產生128bit 或256bit 的雜湊值,如果校驗有問題就要求重傳。
  • 常見問題
  • 使用cookie 時需要考慮的問題
  • 因為儲存在客戶端,容易被客戶端竄改,使用前需要驗證合法性
  • 不要儲存敏感數據,例如使用者密碼,帳戶餘額
  • 使用httpOnly 在一定程度上提高安全性
  • #盡量減少cookie 的體積,能儲存的資料量不能超過4kb
  • 設定正確的domain 和path,減少資料傳輸
  • cookie 無法跨網域

一個瀏覽器針對一個網站最多存20個Cookie,瀏覽器一般只允許存放300 個Cookie

  • 行動端對cookie 的支援不是很好,而session 需要基於cookie 實現,所以行動裝置常用的是token
  • #使用session 時需要考慮的問題
  • 將session 儲存在伺服器裡面,當使用者同時在線量比較多時,這些session 會佔據較多的內存,需要在服務端定期的去清理過期的session
  • 當網站採用叢集部署
  • 的時候,會遇到多台web 伺服器之間如何做session 共享的問題。因為 session 是由單一伺服器創建的,但是處理使用者請求的伺服器不一定是那個創建 session 的伺服器,那麼該伺服器就無法拿到之前已經放入到 session 中的登入憑證之類的資訊了。
  • 當多個應用程式要共用 session 時,除了上述問題,還會遇到跨網域問題,因為不同的應用程式可能部署的主機不一樣,需要在各個應用程式做好 cookie 跨網域的處理。
sessionId 是儲存在 cookie 中的,如果瀏覽器禁止 cookie 或不支援 cookie 怎麼辦?

一般會把sessionId 跟在url 參數後面即重寫url,所以session 不一定要靠cookie 實作

  • 行動端對cookie 的支援不是很好,而session 需要基於cookie實現,所以行動端常用的是token############使用token 時需要考慮的問題#########如果你認為用資料庫來儲存token 會導致查詢時間太長,可以選擇放在記憶體當中。例如 redis 很適合你對 token 查詢的需求。
  • token 完全由應用程式管理,所以它可以避免同源策略
  • token 可以避免CSRF 攻擊(因為不需要cookie 了)
  • 行動端對cookie 的支援不是很好,而session 需要基於cookie 實現,所以行動端常用的是token

使用JWT 時需要考慮的問題

  • 因為JWT 並不依賴Cookie 的,所以你可以使用任何網域提供你的API 服務而不需要擔心跨域資源共享問題(CORS)
  • JWT 默認是不加密,但也是可以加密的。產生原始 Token 以後,可以用金鑰再加密一次。
  • JWT 不加密的情況下,不能將秘密資料寫入 JWT。
  • JWT 不僅可以用於認證,也可以用於交換資訊。有效使用 JWT,可以降低伺服器查詢資料庫的次數。
  • JWT 最大的優勢是伺服器不再需要儲存 Session,使得伺服器認證鑑權業務可以方便擴展。但這也是 JWT 最大的缺點:由於伺服器不需要儲存 Session 狀態,因此使用過程中無法廢棄某個 Token 或更改 Token 的權限。也就是說一旦 JWT 簽發了,到期之前就會始終有效,除非伺服器部署額外的邏輯。
  • JWT 本身包含了認證信息,一旦洩露,任何人都可以獲得該令牌的所有權限。為了減少盜用,JWT的有效期限應該設定得比較短。對於一些比較重要的權限,使用時應該再次對使用者進行認證。
  • JWT 適合一次性的命令認證,頒發一個有效期極短的JWT,即使暴露了危險也很小,由於每次操作都會產生新的JWT,因此也沒必要保存JWT,真正實現無狀態。
  • 為了減少盜用,JWT 不應該使用 HTTP 協定明碼傳輸,要使用 HTTPS 協定傳輸。

使用加密演算法時需要考慮的問題

  • 絕對不要以明文儲存密碼
  • 永遠使用哈希演算法來處理密碼,絕對不要使用Base64 或其他編碼方式來儲存密碼,這和以明文儲存密碼是一樣的,使用哈希,而不要使用編碼。編碼以及加密,都是雙向的過程,而密碼是保密的,應該只被它的所有者知道, 這個過程必須是單向的。哈希正是用來做這個的,從來沒有解哈希這種說法, 但是編碼就存在解碼,加密就存在解密。
  • 絕對不要使用弱雜湊或已破解的雜湊演算法,像 MD5 或 SHA1 ,只使用強密碼雜湊演算法。
  • 絕對不要以明文顯示或發送密碼,即使是密碼的擁有者也應該如此。如果你需要 「忘記密碼」 的功能,可以隨機產生一個新的 一次性的(這點很重要)密碼,然後把這個密碼發送給用戶。

分散式架構下session 共享方案

1. session 複製

  • 任何一個伺服器上的session 發生改變(增刪改),該節點會把這個session 的所有內容序列化,然後廣播給所有其它節點,不管其他伺服器需不需要session ,以此來保證session 同步

優點: 可容錯,各個伺服器間session 能夠即時回應。
缺點: 會對網路負荷造成一定壓力,如果 session 量大的話可能會造成網路阻塞,拖慢伺服器效能。

2. 黏性session /IP 綁定策略

  • 採用Ngnix 中的ip_hash 機制,將某個ip的所有請求都定向到同一台伺服器上,即將用戶與伺服器綁定。 當使用者第一次要求時,負載平衡器將使用者的請求轉發到了A 伺服器上,如果負載平衡器設定了黏性session 的話,那麼使用者以後的每次請求都會轉發到A 伺服器上,相當於把使用者和A 伺服器黏到了一塊,這就是黏性session 機制。

優點: 簡單,不需要對 session 做任何處理。
缺點: 缺乏容錯性,如果目前存取的伺服器發生故障,使用者被轉移到第二個伺服器上時,他的 session 資訊都會失效。
適用場景: 發生故障對客戶產生的影響較小;伺服器發生故障是低機率事件 。
實作方式: 以 Nginx 為例,在 upstream 模組配置 ip_hash 屬性即可實現黏性 session。

3. session 共享(常用)

  • 使用分散式快取方案例如Memcached 、Redis 來快取session,但是要求Memcached 或Redis 必須是叢集
  • 把session 放到Redis 中存儲,雖然架構上變得複雜,並且需要多訪問一次Redis ,但是這種方案帶來的好處也是很大的:
    • 實現了session 共享;
    • #可以水平擴充(增加Redis 伺服器);
    • 伺服器重啟session 不遺失(但也要注意session 在Redis 中的刷新/失效機制);
    • 不僅可以跨伺服器session 共享,甚至可以跨平台(例如網頁端和APP 端)
你還傻傻分不清Cookie、Session、Token、JWT嗎?

#4. session 持久化

  • 將session 存儲到資料庫中,保證session 的持久化

優點: 伺服器出現問題,session 不會遺失
缺點: 如果網站的存取量很大,把session 儲存到資料庫中,會對資料庫造成很大壓力,還需要增加額外的開銷維護資料庫。

只要關掉瀏覽器 ,session 真的就消失了?

不對。對 session 來說,除非程式通知伺服器刪除一個 session,否則伺服器會一直保留,程式一般都是在使用者做 log off 的時候發個指令去刪除 session。
然而瀏覽器從來不會主動在關閉之前通知伺服器它將要關閉,因此伺服器根本不會有機會知道瀏覽器已經關閉,之所以會有這種錯覺,是大部分session 機制都使用會話cookie 來儲存session id,而關閉瀏覽器後這個session id 就消失了,再次連接伺服器時也無法找到原來的session。如果伺服器設定的 cookie 被保存在硬碟上,或使用某種手段改寫瀏覽器發出的 HTTP 請求頭,把原來的 session id 傳送給伺服器,則再次開啟瀏覽器仍然能夠開啟原來的 session。
正是由於關閉瀏覽器不會導致session 被刪除,迫使伺服器為session 設定了一個失效時間,當距離客戶端上一次使用session 的時間超過這個失效時間時,伺服器就認為客戶端已經停止了活動,才會刪除session 以節省儲存空間。

專案位址

在專案中使用JWT

#後語

  • 本文只是基於自己的理解講了理論知識,因為對後端/演算法知識不是很熟,如有謬誤,還請告知,萬分感謝
  • 如果本文對你有所幫助,還請點個讚~~
陳述:
本文轉載於:juejin.im。如有侵權,請聯絡admin@php.cn刪除