Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 Warning: error_log(/data/www/wwwroot/hmttv.cn/caches/error_log.php): failed to open stream: Permission denied in /data/www/wwwroot/hmttv.cn/phpcms/libs/functions/global.func.php on line 537 天天干天天操天天碰,在线观看你懂的网站,国产日本欧美在线观看乱码

          整合營(yíng)銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          「JWT」,你必須了解的認(rèn)證登錄方案

          「JWT」,你必須了解的認(rèn)證登錄方案

          者:古時(shí)的風(fēng)箏

          原文鏈接:https://www.cnblogs.com/fengzheng/p/13527425.html

          JWT 全稱是 JSON Web Token,是目前非常流行的跨域認(rèn)證解決方案,在單點(diǎn)登錄場(chǎng)景中經(jīng)常使用到。

          有些人覺得它非常好用,用了它之后就不用在服務(wù)端借助 redis 實(shí)現(xiàn)認(rèn)證過(guò)程了,但是,還有一部分人認(rèn)為它生來(lái)就有缺陷,根本不能用。

          這是為什么呢?

          傳統(tǒng)的認(rèn)證方式

          從一個(gè)登錄場(chǎng)景說(shuō)起

          你平時(shí)用過(guò)那么多網(wǎng)站和 APP,其中有很多都是需要登錄的吧,那咱們就選一個(gè)場(chǎng)景出來(lái)說(shuō)說(shuō)。

          以一個(gè)電商系統(tǒng)為例,如果你想要下單,首先需要注冊(cè)一個(gè)賬號(hào),擁有了賬號(hào)之后,需要輸入用戶名(比如手機(jī)號(hào)或郵箱)、密碼完成登錄過(guò)程。之后你在一段時(shí)間內(nèi)再次進(jìn)入系統(tǒng),是不需要輸入用戶名和密碼的,只有在連續(xù)長(zhǎng)時(shí)間不登錄的情況下(例如一個(gè)月沒登錄過(guò))訪問(wèn)系統(tǒng),才需要再次輸入用戶名和密碼。

          對(duì)于那些使用頻率很高的網(wǎng)站或應(yīng)用,通常是很長(zhǎng)時(shí)間都不需要輸入密碼的,以至于你在換了一臺(tái)電腦或者一部手機(jī)之后,一些經(jīng)常使用的網(wǎng)站或 APP 的密碼都不記得了。

          早期的 Cookie-Session 認(rèn)證方式

          早期互聯(lián)網(wǎng)以 web 為主,客戶端是瀏覽器 ,所以 Cookie-Session 方式是早期最常用的認(rèn)證方式,直到現(xiàn)在,一些 web 網(wǎng)站依然用這種方式做認(rèn)證。

          認(rèn)證過(guò)程大致如下:

          1. 用戶輸入用戶名、密碼或者用短信驗(yàn)證碼方式登錄系統(tǒng);
          2. 服務(wù)端驗(yàn)證后,創(chuàng)建一個(gè) Session 信息,并且將 SessionID 存到 cookie,發(fā)送回瀏覽器;
          3. 下次客戶端再發(fā)起請(qǐng)求,自動(dòng)帶上 cookie 信息,服務(wù)端通過(guò) cookie 獲取 Session 信息進(jìn)行校驗(yàn);

          但是為什么說(shuō)它是傳統(tǒng)的認(rèn)證方式,因?yàn)楝F(xiàn)在人手一部智能手機(jī),很多人都不用電腦,平時(shí)都是使用手機(jī)上的各種 APP,比如淘寶、拼多多等。
          在這種潮流之下,傳統(tǒng)的 Cookie-Session 就遇到了一些問(wèn)題:
          1、首先,Cookie-Session 只能在 web 場(chǎng)景下使用,如果是 APP 呢,APP 可沒有地方存 cookie。
          現(xiàn)在的產(chǎn)品基本上都同時(shí)提供 web 端和 APP 兩種使用方式,有點(diǎn)產(chǎn)品甚至只有 APP。

          2、退一萬(wàn)步說(shuō),你做的產(chǎn)品只支持 web,也要考慮跨域問(wèn)題, 但Cookie 是不能跨域的。
          拿天貓商城來(lái)說(shuō),當(dāng)你進(jìn)入天貓商城后,會(huì)看到頂部有天貓超市、天貓國(guó)際、天貓會(huì)員這些菜單。而點(diǎn)擊這些菜單都會(huì)進(jìn)入不同的域名,不同的域名下的 cookie 都是不一樣的,你在 A 域名下是沒辦法拿到 B 域名的 cookie 的,即使是子域也不行。

          3、如果是分布式服務(wù),需要考慮 Session 同步問(wèn)題。
          現(xiàn)在的互聯(lián)網(wǎng)網(wǎng)站和 APP 基本上都是分布式部署,也就是服務(wù)端不止一臺(tái)機(jī)器。當(dāng)某個(gè)用戶在頁(yè)面上進(jìn)行登錄操作后,這個(gè)登錄動(dòng)作必定是請(qǐng)求到了其中某一臺(tái)服務(wù)器上。你的身份信息得保存下來(lái)吧,傳統(tǒng)方式就是存 Session。

          接下來(lái),問(wèn)題來(lái)了。你訪問(wèn)了幾個(gè)頁(yè)面,這時(shí),有個(gè)請(qǐng)求經(jīng)過(guò)負(fù)載均衡,路由到了另外一臺(tái)服務(wù)器(不是你登錄的那臺(tái))。當(dāng)后臺(tái)接到請(qǐng)求后,要檢查用戶身份信息和權(quán)限,于是接口開始從從 Session 中獲取用戶信息。但是,這臺(tái)服務(wù)器不是當(dāng)時(shí)登錄的那臺(tái),并沒存你的 Session ,這樣后臺(tái)服務(wù)就認(rèn)為你是一個(gè)非登錄的用戶,也就不能給你返回?cái)?shù)據(jù)了。

          所以,為了避免這種情況的發(fā)生,就要做 Session 同步。一臺(tái)服務(wù)器接收到登錄請(qǐng)求后,在當(dāng)前服務(wù)器保存 Session 后,也要向其他幾個(gè)服務(wù)器同步。

          4、cookie 存在 CSRF(跨站請(qǐng)求偽造)的風(fēng)險(xiǎn)。 跨站請(qǐng)求偽造,是一種挾制用戶在當(dāng)前已登錄的Web應(yīng)用程序上執(zhí)行非本意的操作的攻擊方法。CSRF 利用的是網(wǎng)站對(duì)用戶網(wǎng)頁(yè)瀏覽器的信任。簡(jiǎn)單地說(shuō),是攻擊者通過(guò)一些技術(shù)手段欺騙用戶的瀏覽器去訪問(wèn)一個(gè)自己曾經(jīng)認(rèn)證過(guò)的網(wǎng)站并運(yùn)行一些操作(比如購(gòu)買商品)。由于瀏覽器曾經(jīng)認(rèn)證過(guò),所以被訪問(wèn)的網(wǎng)站會(huì)認(rèn)為是真正的用戶發(fā)起的操作。
          比如說(shuō)我是一個(gè)黑客,我發(fā)現(xiàn)你經(jīng)常訪問(wèn)的一個(gè)技術(shù)網(wǎng)站存在 CSRF 漏洞。發(fā)布文章支持 html 格式,進(jìn)而我在 html 中加入一些危險(xiǎn)內(nèi)容,例如

           <img src="http://www.examplebank.com/withdraw?account=Alice&amount=1000&for=Badman">
          

          假設(shè) src 指向的地址是一個(gè)你平時(shí)用的購(gòu)物網(wǎng)站的付款地址(當(dāng)然只是舉例,真正的攻擊可沒這么簡(jiǎn)單),如果你之前登錄過(guò)并且標(biāo)識(shí)你身份信息的 cookie 已經(jīng)保存下來(lái)了。當(dāng)你刷到我發(fā)布的這篇文章的時(shí)候,img 標(biāo)簽一加載,這個(gè) CSRF 攻擊就會(huì)起作用,在你不知情的情況下向這個(gè)網(wǎng)站付款了。

          Cookie-Session 改造版

          由于傳統(tǒng)的 Cookie-Session 認(rèn)證存在諸多問(wèn)題,那可以把上面的方案改造一下。
          1、改造 Cookie 既然 Cookie 不能在 APP 等非瀏覽器中使用,那就不用 cookie 做客戶端存儲(chǔ),改用其他方式。
          改成什么呢?
          web 中可以使用 local storage,APP 中使用客戶端數(shù)據(jù)庫(kù),這樣既能這樣就實(shí)現(xiàn)了跨域,并且避免了 CSRF 。

          2、服務(wù)端也不存 Session 了,把 Session 信息拿出來(lái)存到 Redis 等內(nèi)存數(shù)據(jù)庫(kù)中,這樣即提高了速度,又避免了 Session 同步問(wèn)題;

          經(jīng)過(guò)改造之后變成了如下的認(rèn)證過(guò)程:

          1. 用戶輸入用戶名、密碼或者用短信驗(yàn)證碼方式登錄系統(tǒng);
          2. 服務(wù)端經(jīng)過(guò)驗(yàn)證,將認(rèn)證信息構(gòu)造好的數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)到 Redis 中,并將 key 值返回給客戶端;
          3. 客戶端拿到返回的 key,存儲(chǔ)到 local storage 或本地?cái)?shù)據(jù)庫(kù);
          4. 下次客戶端再次請(qǐng)求,把 key 值附加到 header 或者 請(qǐng)求體中;
          5. 服務(wù)端根據(jù)獲取的 key,到 Redis 中獲取認(rèn)證信息;

          下面兩張圖分別演示了首次登錄和非首次登錄的過(guò)程。

          經(jīng)過(guò)一頓猛如虎的改造,解決了傳統(tǒng) Cookie-Session 方式存在的問(wèn)題。這種改造需要開發(fā)者在項(xiàng)目中自行完成。改造起來(lái)肯定是費(fèi)時(shí)費(fèi)力的,而且還有可能存在漏洞。

          JWT 出場(chǎng)

          這時(shí),JWT 就可以上場(chǎng)了,JWT 就是一種Cookie-Session改造版的具體實(shí)現(xiàn),讓你省去自己造輪子的時(shí)間,JWT 還有個(gè)好處,那就是你可以不用在服務(wù)端存儲(chǔ)認(rèn)證信息(比如 token),完全由客戶端提供,服務(wù)端只要根據(jù) JWT 自身提供的解密算法就可以驗(yàn)證用戶合法性,而且這個(gè)過(guò)程是安全的。

          如果你是剛接觸 JWT,最有疑問(wèn)的一點(diǎn)可能就是: JWT 為什么可以完全依靠客戶端(比如瀏覽器端)就能實(shí)現(xiàn)認(rèn)證功能,認(rèn)證信息全都存在客戶端,怎么保證安全性?

          JWT 數(shù)據(jù)結(jié)構(gòu)

          JWT 最后的形式就是個(gè)字符串,它由頭部載荷簽名這三部分組成,中間以「.」分隔。像下面這樣:

          頭部

          頭部以 JSON 格式表示,用于指明令牌類型和加密算法。形式如下,表示使用 JWT 格式,加密算法采用 HS256,這是最常用的算法,除此之外還有很多其他的。

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

          對(duì)應(yīng)上圖的紅色 header 部分,需要 Base64 編碼。

          載荷

          用來(lái)存儲(chǔ)服務(wù)器需要的數(shù)據(jù),比如用戶信息,例如姓名、性別、年齡等,要注意的是重要的機(jī)密信息最好不要放到這里,比如密碼等。

          {
            "name": "古時(shí)的風(fēng)箏",
            "introduce": "英俊瀟灑"
          }
          

          另外,JWT 還規(guī)定了 7 個(gè)字段供開發(fā)者選用。

          • iss (issuer):簽發(fā)人
          • exp (expiration time):過(guò)期時(shí)間
          • sub (subject):主題
          • aud (audience):受眾
          • nbf (Not Before):生效時(shí)間
          • iat (Issued At):簽發(fā)時(shí)間
          • jti (JWT ID):編號(hào)

          這部分信息也是要用 Base64 編碼的。

          簽名

          簽名有一個(gè)計(jì)算公式。

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

          使用HMACSHA256算法計(jì)算得出,這個(gè)方法有兩個(gè)參數(shù),前一個(gè)參數(shù)是 (base64 編碼的頭部 + base64 編碼的載荷)用點(diǎn)號(hào)相連,后一個(gè)參數(shù)是自定義的字符串密鑰,密鑰不要暴露在客戶端,而應(yīng)該服務(wù)器知道。

          使用方式

          了解了 JWT 的結(jié)構(gòu)和算法后,那怎么使用呢?假設(shè)我這兒有個(gè)網(wǎng)站。

          1、在用戶登錄網(wǎng)站的時(shí)候,需要輸入用戶名、密碼或者短信驗(yàn)證的方式登錄,登錄請(qǐng)求到達(dá)服務(wù)端的時(shí)候,服務(wù)端對(duì)賬號(hào)、密碼進(jìn)行驗(yàn)證,然后計(jì)算出 JWT 字符串,返回給客戶端。

          2、客戶端拿到這個(gè) JWT 字符串后,存儲(chǔ)到 cookie 或者 瀏覽器的 LocalStorage 中。

          3、再次發(fā)送請(qǐng)求,比如請(qǐng)求用戶設(shè)置頁(yè)面的時(shí)候,在 HTTP 請(qǐng)求頭中加入 JWT 字符串,或者直接放到請(qǐng)求主體中。

          4、服務(wù)端拿到這串 JWT 字符串后,使用 base64的頭部和 base64 的載荷部分,通過(guò)HMACSHA256算法計(jì)算簽名部分,比較計(jì)算結(jié)果和傳來(lái)的簽名部分是否一致,如果一致,說(shuō)明此次請(qǐng)求沒有問(wèn)題,如果不一致,說(shuō)明請(qǐng)求過(guò)期或者是非法請(qǐng)求。

          怎么保證安全性的

          保證安全性的關(guān)鍵就是 HMACSHA256 或者與它同類型的加密算法,因?yàn)榧用苓^(guò)程是不可逆的,所以不能根據(jù)傳到前端的 JWT 傳反解到密鑰信息。

          另外,不同的頭部和載荷加密之后得到的簽名都是不同的,所以,如果有人改了載荷部分的信息,那最后加密出的結(jié)果肯定就和改之前的不一樣的,所以,最后驗(yàn)證的結(jié)果就是不合法的請(qǐng)求。

          別人拿到完整 JWT 還安全嗎

          假設(shè)載荷部分存儲(chǔ)了權(quán)限級(jí)別相關(guān)的字段,強(qiáng)盜拿到 JWT 串后想要修改為更高權(quán)限的級(jí)別,上面剛說(shuō)了,這種情況下是肯定不會(huì)得逞的,因?yàn)榧用艹鰜?lái)的簽名會(huì)不一樣,服務(wù)器可能很容易的判別出來(lái)。

          那如果強(qiáng)盜拿到后不做更改,直接用呢,那就沒有辦法了,為了更大程度上防止被強(qiáng)盜盜取,應(yīng)該使用 HTTPS 協(xié)議而不是 HTTP 協(xié)議,這樣可以有效的防止一些中間劫持攻擊行為。

          有同學(xué)就要說(shuō)了,這一點(diǎn)也不安全啊,拿到 JWT 串就可以輕松模擬請(qǐng)求了。確實(shí)是這樣,但是前提是你怎么樣能拿到,除了上面說(shuō)的中間劫持外,還有什么辦法嗎?

          除非強(qiáng)盜直接拿了你的電腦,那這樣的話,對(duì)不起,不光 JWT 不安全了,其他任何網(wǎng)站,任何認(rèn)證方式都不安全。

          雖然這樣的情況很少,但是在使用 JWT 的時(shí)候仍然要注意合理的設(shè)置過(guò)期時(shí)間,不要太長(zhǎng)。

          一個(gè)問(wèn)題

          JWT 有個(gè)問(wèn)題,導(dǎo)致很多開發(fā)團(tuán)隊(duì)放棄使用它,那就是一旦頒發(fā)一個(gè) JWT 令牌,服務(wù)端就沒辦法廢棄掉它,除非等到它自身過(guò)期。有很多應(yīng)用默認(rèn)只允許最新登錄的一個(gè)客戶端正常使用,不允許多端登錄,JWT 就沒辦法做到,因?yàn)轭C發(fā)了新令牌,但是老的令牌在過(guò)期前仍然可用。這種情況下,就需要服務(wù)端增加相應(yīng)的邏輯。

          常用的 JWT 庫(kù)

          JWT 官網(wǎng)列出了各種語(yǔ)言對(duì)應(yīng)的庫(kù),其中 Java 的如下幾個(gè)。

          以 java-jwt為例。

          1、引入對(duì)應(yīng)的 Maven 包。

          <dependency>
              <groupId>com.auth0</groupId>
              <artifactId>java-jwt</artifactId>
              <version>3.10.3</version>
          </dependency>
          

          2、在登錄時(shí),調(diào)用 create 方法得到一個(gè)令牌,并返回給前端。

          public static String create(){
            try {
              Algorithm algorithm=Algorithm.HMAC256("secret");
              String token=JWT.create()
                .withIssuer("auth0")
                .withSubject("subject")
                .withClaim("name","古時(shí)的風(fēng)箏")
                .withClaim("introduce","英俊瀟灑")
                .sign(algorithm);
              System.out.println(token);
              return token;
            } catch (JWTCreationException exception){
              //Invalid Signing configuration / Couldn't convert Claims.
              throw exception;
            }
          }
          

          3、登錄成功后,再次發(fā)起請(qǐng)求的時(shí)候?qū)?token 放到 header 或者請(qǐng)求體中,服務(wù)端對(duì) token 進(jìn)行驗(yàn)證。

          public static Boolean verify(String token){
            try {
              Algorithm algorithm=Algorithm.HMAC256("secret");
              JWTVerifier verifier=JWT.require(algorithm)
                .withIssuer("auth0")
                .build(); //Reusable verifier instance
              DecodedJWT jwt=verifier.verify(token);
              String payload=jwt.getPayload();
              String name=jwt.getClaim("name").asString();
              String introduce=jwt.getClaim("introduce").asString();
              System.out.println(payload);
              System.out.println(name);
              System.out.println(introduce);
              return true;
            } catch (JWTVerificationException exception){
              //Invalid signature/claims
              return false;
            }
          }
          

          4、用 create 方法生成 token,并用 verify 方法驗(yàn)證一下。

          public static void main(String[] args){
            String token=create();
            Boolean result=verify(token);
            System.out.println(result);
          }
          

          得到下面的結(jié)果

          eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzdWJqZWN0IiwiaW50cm9kdWNlIjoi6Iux5L-K5r2H5rSSIiwiaXNzIjoiYXV0aDAiLCJuYW1lIjoi5Y-k5pe255qE6aOO562dIn0.ooQ1K_XyljjHf34Nv5iJvg1MQgVe6jlphxv4eeFt8pA
          eyJzdWIiOiJzdWJqZWN0IiwiaW50cm9kdWNlIjoi6Iux5L-K5r2H5rSSIiwiaXNzIjoiYXV0aDAiLCJuYW1lIjoi5Y-k5pe255qE6aOO562dIn0
          古時(shí)的風(fēng)箏
          英俊瀟灑
          true
          

          使用 create 方法創(chuàng)建的 JWT 串可以通過(guò)驗(yàn)證。

          而如果我將 JWT 串中的載荷部分,兩個(gè)點(diǎn)號(hào)中間的部分修改一下,然后再調(diào)用 verify 方法驗(yàn)證,會(huì)出現(xiàn) JWTVerificationException異常,不能通過(guò)驗(yàn)證。

          關(guān)面試題如下:

          • 什么是 JWT?為什么要用 JWT?
          • JWT 由哪些部分組成?
          • 如何基于 JWT 進(jìn)行身份驗(yàn)證?
          • JWT 如何防止 Token 被篡改?
          • 如何加強(qiáng) JWT 的安全性?
          • 如何讓 Token 失效?
          • ......

          什么是 JWT?

          JWT (JSON Web Token) 是目前最流行的跨域認(rèn)證解決方案,是一種基于 Token 的認(rèn)證授權(quán)機(jī)制。從 JWT 的全稱可以看出,JWT 本身也是 Token,一種規(guī)范化之后的 JSON 結(jié)構(gòu)的 Token。

          Token 自身包含了身份驗(yàn)證所需要的所有信息,因此,我們的服務(wù)器不需要存儲(chǔ) Session 信息。這顯然增加了系統(tǒng)的可用性和伸縮性,大大減輕了服務(wù)端的壓力。

          可以看出,JWT 更符合設(shè)計(jì) RESTful API 時(shí)的「Stateless(無(wú)狀態(tài))」原則

          并且, 使用 Token 認(rèn)證可以有效避免 CSRF 攻擊,因?yàn)?Token 一般是存在在 localStorage 中,使用 JWT 進(jìn)行身份驗(yàn)證的過(guò)程中是不會(huì)涉及到 Cookie 的。

          我在 JWT 優(yōu)缺點(diǎn)分析[1]這篇文章中有詳細(xì)介紹到使用 JWT 做身份認(rèn)證的優(yōu)勢(shì)和劣勢(shì)。

          下面是 RFC 7519[2] 對(duì) JWT 做的較為正式的定義。

          JSON Web Token (JWT) is a compact, URL-safe means of representing claims to be transferred between two parties. The claims in a JWT are encoded as a JSON object that is used as the payload of a JSON Web Signature (JWS) structure or as the plaintext of a JSON Web Encryption (JWE) structure, enabling the claims to be digitally signed or integrity protected with a Message Authentication Code (MAC) and/or encrypted. ——JSON Web Token (JWT)[3]

          JWT 由哪些部分組成?

          JWT 本質(zhì)上就是一組字串,通過(guò)(.)切分成三個(gè)為 Base64 編碼的部分:

          • Header : 描述 JWT 的元數(shù)據(jù),定義了生成簽名的算法以及 Token 的類型。
          • Payload : 用來(lái)存放實(shí)際需要傳遞的數(shù)據(jù)
          • Signature(簽名) :服務(wù)器通過(guò) Payload、Header 和一個(gè)密鑰(Secret)使用 Header 里面指定的簽名算法(默認(rèn)是 HMAC SHA256)生成。

          JWT 通常是這樣的:xxxxx.yyyyy.zzzzz

          示例:

          eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.
          eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.
          SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
          

          你可以在 jwt.io[4] 這個(gè)網(wǎng)站上對(duì)其 JWT 進(jìn)行解碼,解碼之后得到的就是 Header、Payload、Signature 這三部分。

          Header 和 Payload 都是 JSON 格式的數(shù)據(jù),Signature 由 Payload、Header 和 Secret(密鑰)通過(guò)特定的計(jì)算公式和加密算法得到。

          Header

          Header 通常由兩部分組成:

          • typ(Type):令牌類型,也就是 JWT。
          • alg(Algorithm) :簽名算法,比如 HS256。

          示例:

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

          JSON 形式的 Header 被轉(zhuǎn)換成 Base64 編碼,成為 JWT 的第一部分。

          Payload

          Payload 也是 JSON 格式數(shù)據(jù),其中包含了 Claims(聲明,包含 JWT 的相關(guān)信息)。

          Claims 分為三種類型:

          • Registered Claims(注冊(cè)聲明) :預(yù)定義的一些聲明,建議使用,但不是強(qiáng)制性的。
          • Public Claims(公有聲明) :JWT 簽發(fā)方可以自定義的聲明,但是為了避免沖突,應(yīng)該在 IANA JSON Web Token Registry[5] 中定義它們。
          • Private Claims(私有聲明) :JWT 簽發(fā)方因?yàn)轫?xiàng)目需要而自定義的聲明,更符合實(shí)際項(xiàng)目場(chǎng)景使用。

          下面是一些常見的注冊(cè)聲明:

          • iss(issuer):JWT 簽發(fā)方。
          • iat(issued at time):JWT 簽發(fā)時(shí)間。
          • sub(subject):JWT 主題。
          • aud(audience):JWT 接收方。
          • exp(expiration time):JWT 的過(guò)期時(shí)間。
          • nbf(not before time):JWT 生效時(shí)間,早于該定義的時(shí)間的 JWT 不能被接受處理。
          • jti(JWT ID):JWT 唯一標(biāo)識(shí)。

          示例:

          {
            "uid": "ff1212f5-d8d1-4496-bf41-d2dda73de19a",
            "sub": "1234567890",
            "name": "John Doe",
            "exp": 15323232,
            "iat": 1516239022,
            "scope": ["admin", "user"]
          }
          

          Payload 部分默認(rèn)是不加密的,一定不要將隱私信息存放在 Payload 當(dāng)中!!!

          JSON 形式的 Payload 被轉(zhuǎn)換成 Base64 編碼,成為 JWT 的第二部分。

          Signature

          Signature 部分是對(duì)前兩部分的簽名,作用是防止 Token(主要是 payload) 被篡改。

          這個(gè)簽名的生成需要用到:

          • Header + Payload。
          • 存放在服務(wù)端的密鑰(一定不要泄露出去)。
          • 簽名算法。

          簽名的計(jì)算公式如下:

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

          算出簽名以后,把 Header、Payload、Signature 三個(gè)部分拼成一個(gè)字符串,每個(gè)部分之間用"點(diǎn)"(.)分隔,成為 JWT 的第三部分。

          如何基于 JWT 進(jìn)行身份驗(yàn)證?

          在基于 Token 進(jìn)行身份驗(yàn)證的的應(yīng)用程序中,服務(wù)器通過(guò) Payload、Header 和Secret(密鑰)創(chuàng)建Token(令牌)并將 Token 發(fā)送給客戶端。客戶端接收到 Token 之后,會(huì)將其保存在 Cookie 或者 localStorage 里面,以后客戶端發(fā)出的所有請(qǐng)求都會(huì)攜帶這個(gè)令牌。

          簡(jiǎn)化后的步驟如下:

          1. 用戶向服務(wù)器發(fā)送用戶名、密碼以及驗(yàn)證碼用于登陸系統(tǒng)。
          2. 如果用戶用戶名、密碼以及驗(yàn)證碼校驗(yàn)正確的話,服務(wù)端會(huì)返回已經(jīng)簽名的 Token
          3. 用戶以后每次向后端發(fā)請(qǐng)求都在 Header 中帶上這個(gè) Token
          4. 服務(wù)端檢查 Token 并從中獲取用戶相關(guān)信息。

          兩點(diǎn)建議:

          1. 建議將 Token 存放在 localStorage 中,放在 Cookie 中會(huì)有 CSRF 風(fēng)險(xiǎn)。
          2. 請(qǐng)求服務(wù)端并攜帶 Token 的常見做法是將 Token 放在 HTTP Header 的 Authorization 字段中(Authorization: Bearer Token)。

          spring-security-jwt-guide[6] 就是一個(gè)基于 JWT 來(lái)做身份認(rèn)證的簡(jiǎn)單案例,感興趣的可以看看。

          JWT 如何防止 Token 被篡改?

          有了簽名之后,即使 Token 被泄露或者解惑,黑客也沒辦法同時(shí)篡改 Signature 、Header 、Payload。

          這是為什么呢?因?yàn)榉?wù)端拿到 Token 之后,會(huì)解析出其中包含的 Header、Payload 以及 Signature 。服務(wù)端會(huì)根據(jù) Header、Payload、密鑰再次生成一個(gè) Signature。拿新生成的 Signature 和 Token 中的 Signature 作對(duì)比,如果一樣就說(shuō)明 Header 和 Payload 沒有被修改。

          不過(guò),如果服務(wù)端的秘鑰也被泄露的話,黑客就可以同時(shí)篡改 Signature 、Header 、Payload 了。黑客直接修改了 Header 和 Payload 之后,再重新生成一個(gè) Signature 就可以了。

          密鑰一定保管好,一定不要泄露出去。JWT 安全的核心在于簽名,簽名安全的核心在密鑰。

          如何加強(qiáng) JWT 的安全性?

          1. 使用安全系數(shù)高的加密算法。
          2. 使用成熟的開源庫(kù),沒必要造輪子。
          3. Token 存放在 localStorage 中而不是 Cookie 中,避免 CSRF 風(fēng)險(xiǎn)。
          4. 一定不要將隱私信息存放在 Payload 當(dāng)中。
          5. 密鑰一定保管好,一定不要泄露出去。JWT 安全的核心在于簽名,簽名安全的核心在密鑰。
          6. Payload 要加入 exp (JWT 的過(guò)期時(shí)間),永久有效的 JWT 不合理。并且,JWT 的過(guò)期時(shí)間不易過(guò)長(zhǎng)。
          7. ......

          參考資料

          [1]

          JWT 優(yōu)缺點(diǎn)分析: ./advantages&disadvantages-of-jwt.md

          [2]

          RFC 7519: https://tools.ietf.org/html/rfc7519

          [3]

          JSON Web Token (JWT): https://tools.ietf.org/html/rfc7519

          [4]

          jwt.io: https://jwt.io/

          [5]

          IANA JSON Web Token Registry: https://www.iana.org/assignments/jwt/jwt.xhtml

          [6]

          spring-security-jwt-guide: https://github.com/Snailclimb/spring-security-jwt-guide

          本文內(nèi)容來(lái)源于官方網(wǎng)站,讓我們來(lái)了解下JWT

          官網(wǎng)地址

          https://jwt.io/

          什么是JWT?

          JWT是一個(gè)開放標(biāo)準(zhǔn)(RFC 7519),完整的名稱是JSON Web Token,以下都簡(jiǎn)稱JWT,它是一種緊湊且獨(dú)立的以JSON對(duì)象的形式在各種場(chǎng)景下安全地傳輸信息。因?yàn)樗菙?shù)字簽名的,可以對(duì)它進(jìn)行驗(yàn)證。可以使用一個(gè)秘密對(duì)JWT進(jìn)行簽名(使用HMAC算法)或使用RSA或ECDSA。

          什么時(shí)候應(yīng)該使用JWT?

          以下是一些適合使用JWT的場(chǎng)景:

          • 授權(quán)

          認(rèn)證授權(quán)是使用JWT最常見的場(chǎng)景。一旦用戶登錄,每個(gè)后續(xù)請(qǐng)求都將包括JWT,允許用戶訪問(wèn)該令牌允許的路由、服務(wù)和資源。單點(diǎn)登錄是當(dāng)今廣泛使用的一種特性,因?yàn)樗_銷小,而且能夠很容易在不同的域下使用,也就是我們常說(shuō)的跨域。

          • 信息交換

          JWT是在各場(chǎng)景之間安全地傳輸信息的一種好方法。因?yàn)镴WT可以進(jìn)行簽名,例如,使用公鑰/私鑰對(duì),你可以根據(jù)公鑰/私鑰對(duì)來(lái)判斷請(qǐng)求信息是否有效。此外,由于簽名是使用報(bào)頭和負(fù)載計(jì)算的,你還可以驗(yàn)證內(nèi)容有沒有被篡改。

          JWT的結(jié)構(gòu)

          JWT以其緊湊的形式由點(diǎn)分隔的三個(gè)部分組成(.),它們是:

          • Header(標(biāo)頭)
          • Payload(負(fù)載)
          • Signature(簽名)

          因此,JWT通常是下面這樣的形勢(shì)

          Header.Payload.Signature

          我們針對(duì)不同的部分別來(lái)介紹:

          標(biāo)頭(Header):

          標(biāo)頭典型由兩個(gè)部分組成:令牌的類型(即JWT)正在使用的簽名算法(如HMAC SHA 256或RSA)。

          例如:

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

          負(fù)載(Payload)

          令牌的第二部分是負(fù)載,它包含了以下部分:

          • iss (issuer):簽發(fā)人
          • exp (expiration time):過(guò)期時(shí)間
          • sub (subject):主題
          • aud (audience):受眾
          • nbf (Not Before):生效時(shí)間
          • iat (Issued At):簽發(fā)時(shí)間
          • jti (JWT ID):編號(hào)

          除了官方提供的字段之外,你還可以自定義字段:

          {
           "sub": "1234567890",
           "name": "John Doe",
           "admin": true
          }
          

          注意:對(duì)于簽名的令牌,這些信息雖然受到保護(hù),但任何人都可以閱讀。除非加密,否則不要將秘密信息放入JWT的有效負(fù)載或頭元素中,如登錄密碼等。

          簽名

          要?jiǎng)?chuàng)建簽名部分,你必須接受編碼的頭部、編碼的負(fù)載、表頭中的加密算法,并對(duì)其進(jìn)行簽名。

          例如,如果要使用HMAC SHA 256算法,則將以下列方式創(chuàng)建簽名:

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

          簽名用于驗(yàn)證消息在過(guò)程中沒有被更改,對(duì)于用私鑰簽名的令牌,它還可以驗(yàn)證JWT的發(fā)送方是否是它所稱的發(fā)送方。

          Base64Url

          生成的結(jié)果是三個(gè)Base64-URL字符串,由點(diǎn)分隔,可以在HTML和HTTP環(huán)境中輕松地傳遞,同時(shí)與基于XML的標(biāo)準(zhǔn)(如SAML)相比更加緊湊。

          JWT是如何做到有效驗(yàn)證的?

          在身份驗(yàn)證中,當(dāng)用戶成功地使用他們的憑據(jù)登錄時(shí),將返回一個(gè)JWT。由于令牌是憑據(jù),因此必須非常小心地防止安全問(wèn)題。通常,你不應(yīng)將令牌保存的時(shí)間超過(guò)所需時(shí)間。

          每當(dāng)用戶想訪問(wèn)受保護(hù)的路由或資源時(shí),用戶代理應(yīng)該發(fā)送JWT,通常在請(qǐng)求頭帶上如下:

          Authorization: Bearer <token>
          

          在某些情況下,這可能是一種無(wú)狀態(tài)授權(quán)機(jī)制。服務(wù)器的受保護(hù)路由將在授權(quán)標(biāo)頭,如果它存在,則允許用戶訪問(wèn)受保護(hù)的資源。如果JWT包含必要的數(shù)據(jù),那么查詢數(shù)據(jù)庫(kù)中某些操作的需求可能會(huì)減少,盡管情況可能并不總是這樣。

          下圖顯示了如何獲取JWT并用于訪問(wèn)API或資源:

          1. 應(yīng)用程序或客戶端向授權(quán)服務(wù)器請(qǐng)求授權(quán)。這是通過(guò)不同的授權(quán)流之一執(zhí)行的。例如一個(gè)典型的OpenID連接兼容的web應(yīng)用程序?qū)⑼ㄟ^(guò)/oauth/authorize端點(diǎn)使用授權(quán)碼流.
          2. 當(dāng)授權(quán)被授予時(shí),授權(quán)服務(wù)器將訪問(wèn)令牌返回給應(yīng)用程序。
          3. 應(yīng)用程序使用訪問(wèn)令牌訪問(wèn)受保護(hù)的資源(如API)。
          4. JWT通常可以存放在cookies或者localStorage中

          請(qǐng)注意,使用簽名的令牌,令牌中包含的所有信息都將公開給用戶或其他各方,即使他們無(wú)法更改它。這意味著不應(yīng)該將秘密信息放入令牌中。

          總結(jié)一下

          JWT在當(dāng)前的Web或HTTP應(yīng)用開發(fā)中非常受用,本文通過(guò)介紹JWT能讓我們更容易的理解什么是JWT,以及如何使用,并且JWT的工作原理,JWT針對(duì)各個(gè)平臺(tái)都有對(duì)應(yīng)的多個(gè)可選框架使用,因此在理解了JWT的結(jié)構(gòu)和原理之后,我們可以更加簡(jiǎn)單的使用它,如果本文對(duì)你有幫助,請(qǐng)麻煩幫忙轉(zhuǎn)發(fā)、點(diǎn)贊加關(guān)注哦!謝謝!


          主站蜘蛛池模板: 国产一区二区三区在线观看精品| 亚洲日本va一区二区三区| 3d动漫精品成人一区二区三| 国产高清视频一区二区| 国产AV午夜精品一区二区三| 午夜一区二区在线观看| 色狠狠AV一区二区三区| 日本一区二区在线免费观看| 日韩毛片基地一区二区三区| 亚洲线精品一区二区三区| 亚洲一区二区精品视频| 精品久久久中文字幕一区| 国产日韩一区二区三区| 日韩一区二区在线观看视频| 日韩精品人妻一区二区中文八零 | 色噜噜狠狠一区二区三区果冻| 福利一区国产原创多挂探花| 无码人妻精品一区二区三区不卡| 3d动漫精品啪啪一区二区中文| 亚洲中文字幕无码一区| 日韩免费视频一区二区| 波多野结衣免费一区视频| 亚洲一区二区三区AV无码| 中文字幕一区二区人妻性色| 国产日韩一区二区三免费高清 | 亚洲av高清在线观看一区二区| 国产一区中文字幕| 精品理论片一区二区三区| 国产一区二区三区精品久久呦| 精品在线一区二区| 亚洲片国产一区一级在线观看| 一区二区三区观看| 香蕉视频一区二区三区| 国产午夜精品一区二区三区嫩草 | 亚洲中文字幕久久久一区| 亚洲AV成人精品日韩一区| 亚洲av色香蕉一区二区三区蜜桃| 另类国产精品一区二区| 国产乱子伦一区二区三区| 国产午夜精品一区二区三区小说| 国产激情无码一区二区三区|