天天看點

淺談JWT

一、JWT簡介

        JWT(JSON WEB TOKEN)是一個基于JSON的公開規範(RFC 7519),它定義了一種緊湊的、自包含的方式,用于作為JSON對象在各方之間安全地傳輸資訊。該資訊使用了數字簽名,可以被驗證與信任。

二、應用場景

  • Authorization(授權):JWT最常見的應用場景,一旦使用者登入,後續每個請求都将包含JWT,允許使用者通路該令牌允許的路由、服務和資源。單點登入是現在廣泛使用的JWT的一個特性,因為它的開銷很小,并且可以輕松地跨域使用。
  • Information Exchange (資訊交換) : JWT也可用于在各方之間安全的傳輸資訊 。因為JWT使用了數字簽名。例如,使用公鑰/私鑰對,就可對發送人加以驗證。另外,簽名是使用請求頭和求求内容計算得到的,是以還可以驗證内容沒有被篡改。

三、JWT的結構

    JSON Web Token由三部分組成,它們之間用圓點(.)連接配接。這三部分分别是:

  • Header
  • Payload
  • Signature

    一個典型的JWT的形式如下所示:

aaaa.bbbbbbbbbb.cccccc
           

    具體到每一部分:

1. Header

        Header典型的由兩部分組成:token的類型(“JWT”)和算法名稱(比如:HMAC SHA256或者RSA等等)。

{
    'alg': "HS256",
    'typ': "JWT"
}
           

        然後,用Base64對這個JSON編碼就得到JWT的第一部分.

2. Payload

        JWT的第二部分是payload,它是關于實體(通常是使用者)和其他資料的聲明。聲明有三種類型: registered, public 和 private。

  • Registered claims : 這裡有一組預定義的聲明,使用時推薦,但不強制。比如:iss (issuer 釋出者), exp(expiration time 有效期), sub (subject 主題), aud (audience)等。
  • Public claims : 此類型聲明可以随意定義。
  • Private claims : 不屬于公開或者注冊的聲明,用在各方約定好并同意在各方之間共享資訊所使用的聲明。

    一個示例:

{
    "exp":1625309676,
    "user_name":"liuzhihao",
    "jti":"2ddc8367-b4ba-448b-a282-c52cc04c289d",
    "client_id":"browser",
    "scope":[
        "all"
    ],
    "ip":"172.21.72.116"
}
           

      用Base64對Payload這個JSON編碼就得到JWT的第二部分。

      由于base64可被解碼因而被擷取到所包含的資訊,是以不建議在payload或header中放置敏感資訊,除非它們是加密的。

3. Signature

      将編碼過的header與編碼過的payload使用header所聲明的算法名稱對它們簽名,即可得到第三部分。

     格式示例:

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
           

     簽名用于驗證消息在傳遞過程中有沒有被更改,而且對于使用私鑰簽名的token,它還可以驗證JWT的發送方的身份。

     生成一條完整的JWT示例:

淺談JWT

四、JWT的使用

       在認證時,當使用者用他們的憑證成功登入以後,會擷取到一個傳回的JWT。此後,Token就是使用者憑證了,但必須小心防止出現安全問題。一般而言,Token有效期不應超過你需要使用它的時間。

       無論何時使用者想要通路受保護的路由或者資源的時候,使用者代理(通常是浏覽器)都應該帶上JWT。通常JWT放在Authorization header中,用bearer schema。

header通常為這種形式:

Authorization: Bearer
           

       伺服器上的受保護的路由将會檢查Authorization header中的JWT是否有效。如果有效,則使用者可以通路受保護的資源。如果JWT包含着足夠多的必要的求取資料,那麼就可以減少服務端去資料庫查詢的很多操作。

       如果token是在授權頭(Authorization header)中發送的,那麼跨源資源共享(CORS)将不會成為問題,因為它不使用cookie。

五、 基于Token的身份認證 與 基于伺服器的身份認證

1.基于伺服器的身份認證

HTTP協定是無狀态的。也就是說,我第一次登陸時已經認證了一個使用者,但是當我第二次登陸發送請求的時候,伺服器依然不知道我是誰,我必須再次認證。

       傳統的做法是将已經認證過的使用者資訊存儲在伺服器上,比如Session。使用者下次請求的時候帶着Session ID,然後伺服器檢查Session 确認使用者是否認證過。

這種基于伺服器的身份認證方式存在一些問題:

  • Sessions :

    每次使用者認證通過以後,伺服器需要建立一條記錄儲存使用者資訊,通常是在記憶體中,随着認證通過的使用者越來越多,伺服器的在這裡的開銷就會越來越大。

  • Scalability : 由于Session是在記憶體中的,這就帶來一些擴充性的問題。
  • CORS :

    當我們想要擴充我們的應用,讓我們的資料被多個移動裝置使用時,我們必須考慮跨資源共享問題。當使用AJAX調用從另一個域名下擷取資源時,我們可能會遇到禁止請求的問題。

  • CSRF : 使用者很容易受到CSRF攻擊。

2.JWT與Session的異同

  • JWT和Session都是存儲使用者資訊的載體,但是Session是存儲在伺服器端的,而JWT是存儲在用戶端的。
  • 方式存儲使用者資訊的最大問題在于要占用大量伺服器記憶體,增加伺服器的開銷;而JWT方式将使用者狀态分散到了用戶端中,可以明顯減輕服務端的記憶體壓力。
  • Session的狀态存儲在伺服器端,用戶端隻有session id;而Token的狀态存儲在用戶端。
    淺談JWT

3.基于Token的身份認證

基于Token的身份認證是無狀态的,伺服器中不會存儲任何使用者資訊。

沒有會話資訊意味着應用程式可以根據需要擴充和添加更多的機器,而不必擔心使用者登入的位置。

這一實作的主要流程如下:

  1. 使用者攜帶使用者名和密碼請求通路
  2. 伺服器校驗使用者憑據
  3. 應用提供一個token給用戶端
  4. 用戶端存儲token,并且在随後的每一次請求中都帶着它
  5. 伺服器校驗token并傳回資料

注意:

  • 每一次請求都需要token
  • Token應該放在請求header中
  • 我們還需要将伺服器設定為接受來自所有域的請求,用Access-Control-Allow-Origin: *
淺談JWT

4.Token的優勢

  • 無狀态和可擴充性:Tokens存儲在用戶端。完全無狀态,可擴充。我們的負載均衡器可以将使用者傳遞到任意伺服器,因為在任何地方都沒有狀态或會話資訊。
  • 安全:Token并不是Cookie,每次請求的時候Token都會被發送。而且,由于沒有Cookie被發送,還有助于防止CSRF攻擊。即使在你的實作中将token存儲到用戶端的Cookie中,這個Cookie也隻是一種存儲機制,而非身份認證機制。沒有基于會話的資訊可以操作,因為我們沒有會話。

還有一點,token在一段時間以後會過期,這個時候使用者需要重新登入。這有有利于安全性。還有一個概念叫token撤銷,它允許我們根據相同的授權許可使特定的token甚至一組token無效。

5. JWT與OAuth的差別

  • OAuth2是一種授權架構 ,JWT是一種認證協定
  • 無論使用哪種方式切記用HTTPS來保證資料的安全性
  • OAuth2用在使用第三方賬号登入的情況(比如使用weibo, qq, github登入某個app),而JWT是用在前後端分離, 需要簡單的對背景API進行保護時使用。

繼續閱讀