資安

IdentityServer4之JWT簽名(RSA加密證書)及驗籤

一、前言
在IdentityServer4中有兩種令牌,一個是JWT和Reference Token,在IDS4中默認用的是JWT,那麼這兩者有什麼區別呢?

二、JWT與Reference Token的區別
1、JWT(不可撤回)  

  JWT是一個非常輕巧的規範,一般被用來在身份提供者和服務提供者間傳遞安全可靠的信息。JWT令牌是一個自包含的訪問令牌 - 它是一個帶有聲明和過期的受保護數據結構。一旦API瞭解了密鑰材料,它就可以驗證自包含的令牌,而無需與發行者進行通信。這使得JWT難以撤銷。它們將一直有效,直到它們過期。

  JWT常被用於前後端分離,可以和 Restful API 配合使用,常用於構建身份認證機制,一個 JWT 實際上就是一個字符串,它包含了使用.分隔的三部分: Header 頭部 Payload 負載 Signature 簽名(格式:Header.Payload.Signature)

在這個三個部分中最關鍵的就是signature。

  signature:被用來確認JWT信息的發送者是誰,並保證信息沒有被篡改,使用header中指定的算法將編碼後的header、編碼後的payload、一個secret進行加密。因此簽名算法推薦使用RSA或ECDSA非對稱加密算法。

JWT特點:

  A、JWT 默認是不加密,但也是可以加密的。生成原始 Token 以後,可以用密鑰再加密一次。

  B、為了減少盜用,JWT 不應該使用 HTTP 協議明碼傳輸,要使用 HTTPS 協議傳輸

  C、jwt去中心化的思想:api資源收到第一個請求之後,會去id4服務器獲取公鑰,然後用公鑰驗證token是否合法,如果合法進行後面的有效性驗證。有且只有第一個請求才會去id4服務器請求公鑰,後面的請求都會用第一次請求的公鑰來驗證,這也是jwt去中心化驗證的思想。(注:如果簽名證書發生改變則需要重啟有請求ids4服務器的資源服務器。)

  D、JWT 本身包含了認證信息,一旦洩露,任何人都可以獲得該令牌的所有權限。為了減少盜用,JWT 的有效期應該設置得比較短。對於一些比較重要的權限,使用時應該再次對用戶進行認證。

2、Reference Token(不攜帶任何用戶數據,可撤回)

  當使用 Reference token 的時候,服務端會對 Token 進行持久化,當客戶端請求資源端(API)的時候,資源端需要每次都去服務端通信去驗證 Token 的合法性[/connect/introspect],IdentityServer4.AccessTokenValidation 中間件中可以配置緩存一定的時候去驗證,並且 Token 是支持撤銷[/connect/revocation]的。

  使用引用令牌時 - IdentityServer會將令牌的內容存儲在數據存儲中,並且只會將此令牌的唯一標識符發回給客戶端。接收此引用的API必須打開與IdentityServer的反向通道通信以驗證令牌。如下:access_token就是唯一標識。(注不攜帶任何數據)
1.png

  當 AccessTokenType 定義為 Reference 的時候,驗證資源端要注意配置 ApiSecrets 以確保 POST /connect/introspect HTTP/1.1 接口能驗證通過,當 AccessTokenType 定義為 Jwt 的時候則資源端可不配置 options.ApiSecret 選項。如下圖:

2.png

Reference Token官方圖如下:
3.png

以上就是JWT與Reference token的區別。為了減少訪問中心服務器的資源,使用JWT還是非常棒的,畢竟與服務器交互的資源還是非常的昂貴的。不過具體的還得視實際情況而定。

那麼我們來看一下在IDS4中API使用JWT以及Reference Token的交互流程圖

三、IDS4中API使用JWT以及Reference Token與認證中心的交互流程圖
此圖為:JWT,當然大家可以通過fiddler 抓包工具來查看一下具體的數據流就能明白其中的道理。

注:資源服務器在第一次解析AccessToken的時候會先到授權服務器獲取配置數據(例如會訪問:http://localhost:5000/.well-known/openid-configuration 獲取配置的,http://localhost:5000/.well-known/openid-configuration/jwks 獲取jwks)),之後解析AccessToken都會使用第一次獲取到的配置數據,因此如果授權服務的配置更改了(加密證書等等修改了),那麼應該重啟資源服務器使之重新獲取新的配置數據;
4.png

此圖為:Reference Token
5.png

以上即JWT與Reference Token 流程圖。

四、JWT中使用RSA加密
在說明JWT使用RSA加密之前我們先來比較一下其他的加密算法

1、HS256與RS256的區別

  HS256 使用密鑰生成固定的簽名,RS256 使用成非對稱進行簽名。簡單地說,HS256 必須與任何想要驗證 JWT的 客戶端或 API 共享祕密。即 如下圖

6.png

  RS256 生成非對稱簽名,這意味著必須使用私鑰來籤簽名 JWT,並且必須使用對應的公鑰來驗證簽名。與對稱算法不同,使用 RS256 可以保證服務端是 JWT 的簽名者,因為服務端是唯一擁有私鑰的一方。這樣做將不再需要在許多應用程序之間共享私鑰

2、創建自簽名證書(操作步驟)

  生產環境(負載集群)一般需要使用固定的證書籤名與驗籤,以確保重啟服務端或負載的時候 Token 都能驗籤通過。(不使用臨時證書)

那麼證書如何生成請看下面分解步驟:

  第一種:使用OpenSSL生成證書,注:RSA加密證書長度要2048以上,否則服務運行會拋異常

Linux系統生成證書:(推薦使用)
sudo yum install openssl (CentOS)

生成私鑰文件
openssl genrsa -out idsrv4.key 2048

創建證書籤名請求文件 CSR(Certificate Signing Request),用於提交給證書頒發機構(即 Certification Authority (CA))即對證書籤名,申請一個數字證書。
openssl req -new -key idsrv4.key -out idsrv4.csr

生成自簽名證書(證書頒發機構(CA)簽名後的證書,因為自己做測試那麼證書的申請機構和頒發機構都是自己,crt 證書包含持有人的信息,持有人的公鑰,以及簽署者的簽名等信息。當用戶安裝了證書之後,便意味著信任了這份證書,同時擁有了其中的公鑰。)
openssl x509 -req -days 365 -in idsrv4.csr -signkey idsrv4.key -out idsrv4.crt (包含公鑰)

自簽名證書與私匙合併成一個文件(注:.pfx中可以加密碼保護,所以相對安全些)
openssl pkcs12 -export -in idsrv4.crt -inkey idsrv4.key -out idsrv4.pfx (注:在生成的過程中會讓我們輸入Export Password)
證書截圖如下:
7.png

  第二種:

openssl req -newkey rsa:2048 -nodes -keyout idsrv4.key -x509 -days 365 -out idsrv4.cer
openssl pkcs12 -export -in idsrv4.cer -inkey idsrv4.key -out idsrv4.pfx

生成如下:

8.png

3、證書生成之後就可進入VS2017中配置

拷貝生成的證書,放到認證/授權服務器項目中。(VS中配置文件設置文件始終複製),最後把證書路徑和密碼配置到 IdentityServer 中,因為我們自簽名的證書是 PKCS12 (個人數字證書標準,Public Key Cryptography Standards #12) 標準包含私鑰與公鑰)標準,包含了公鑰和私鑰。

A、在appsetting.json 配置文件中添加如下:此處需要配置password,自定義即可。

9.png

B、在starup.cs中ConfigureServices方法中配置如下即可。

10.png

配置完後即可。我們啟動IDS4項目即可生成加密的token。

11.png

將得到的token在jwt.io 網站來認證一下:把後綴為 crt 公鑰、key私鑰複製到驗證中,發現認證ok。這樣即可實現防篡改。

12.png

五、總結
在實際環境中應該使用加密的token,而不應該使用臨時令牌。以及儘量設置token的過期時間短,以及刷新token的機制,這樣可以儘可能的保護token以及數據安全。

Leave a Reply

Your email address will not be published. Required fields are marked *