【譯】如何為應用程序選擇 JOSE / JWT 加密算法

本文翻譯自 How to select a JOSE / JWT cryptographic algorithm for your application

JOSE 即 JavaScript Object Signing and Encryption,已采用了一系列標準加密算法,包括新的 Edwards 曲線算法(2017年新增)。那么應該使用哪種算法來保護 JWT 或應用程序中的其他對象呢?本指南將提供一些基本準則,以便做出明智的選擇。 但是,也請咨詢該領域的文章,文獻和專家,以仔細檢查您的假設,并確保沒有遺漏任何重要問題。

一、常見的數據安全關注點

我們保護數據(例如令牌)的需求通常來自一個或多個關注的問題:

  • 完整性
    關注數據未被篡改
  • 真實性
    關注可以驗證數據的來源
  • 不可抵賴
    數據的來源必須可由其他人驗證
  • 保密
    對未經授權的各方和操作保密

選擇合適的 JOSE 算法的第一步,是了解我們所關注的安全因素。

二、可用的 JOSE 算法類

JOSE 提供了三種截然不同的加密算法類,以解決四個安全問題,它們具有部分重疊的屬性:

算法 完整性 真實性 不可抵賴性 保密性
HMAC ? ?
數字簽名 ? ? ?
認證加密 ? ? ?

HMAC 算法:一種特殊的超高效哈希(HMAC),用于確保數據的完整性和真實性。 為了計算 HMAC,您需要一個密鑰

數字簽名:提供 HMAC 的特性,以及加密的不可否認性(使簽名者以外的其他人可以檢查簽名的有效性)。 數字簽名基于公鑰/私鑰密碼術。 需要一對公鑰/私鑰(類型為 RSA,橢圓曲線(EC)或愛德華茲曲線八位密鑰對(OKP))。

認證加密:在加密數據的同時,還確保其完整性和真實性(例如 HMAC)。 JOSE 通過公鑰/私鑰,秘密(共享)密鑰和密碼來提供加密。

1、基于哈希的消息認證碼(HMAC)

  • 功能:完整性、認證
  • JOSE 格式:JSON Web Signature(JWS)
  • 秘鑰類型:密碼
  • 算法:HMAC with SHA-2
    • HS256
    • HS384
    • HS512
  • 用例:
    • 存儲在瀏覽器 Cookie 中的無狀態會話
    • 電子郵件驗證碼
    • 會話 ID 能夠區分過期 ID 和無效 ID
    • Token 的頒發者最終用戶是==同一角色==
  • 備注
    • HMAC 不是數字簽名!
    • 使用更長的密鑰/哈希(例如 HS512 )以提高安全性
    • 長于哈希大小的密鑰不能提供額外的安全性

對于令牌和其他需要向外發送或存儲的信息,如果最終由頒發它的應用程序使用,那么 HMAC 算法(帶有 JOSE alg 標識符 HS256,HS384 和 HS512)是理想的選擇。

這里的主要關注點是確保:
1)當我們取回數據時數據的完整性,以及
2)數據實際上是由我們產生的。

示例 JWT 聲明了無狀態會話 Cookie:

{
  "sub"      : "user-12345",
  "email"    : "alice@wonderland.net",
  "login_ip" : "172.16.254.1", 
  "exp"      : 1471102267
}

一個常見的誤解,是消息身份驗證代碼可以視為數字簽名。 其實并不是! 這是因為驗證的過程需要用到計算 HMAC 時使用的原始密鑰,并且從本質上講,該密鑰不能與他人分享,因為不能讓他人具備生成自己的 HMAC 的能力。 如果想要不可否認性,請使用 RSA,EC 或 EdDSA 簽名

2、數字簽名

數字簽名適用于發行令牌、聲明、斷言和文檔,且這些文檔的完整性和真實性必須由其他各方進行驗證的場景。

使用示例:
  • 由 OpenID 提供者發行的身份令牌,依賴方需要對其進行驗證才能登錄用戶。
  • 由 OAuth 2.0 服務器發出的訪問令牌,資源服務器 / Web API 必須在提供請求之前對其進行驗證。
數字簽名僅適用于公用/專用密鑰:
  • 頒發者需要先生成 公鑰/私鑰對,然后才能對 JWT 或其他對象進行簽名。
  • 簽名是用私鑰計算的,私鑰必須始終保持安全,否則會有冒充的風險。
  • JWT 或 JWS 對象的簽名需要使用公鑰驗證。接收者發現和下載公鑰的方法是特定于應用程序的。 例如,OpenID Connect 服務器JWK 格式的 URL 上發布其公鑰。
選擇哪種數字簽名算法?
  • 如果您需要廣泛的支持,請選擇 RS256。 該算法基于 RSA PKCS#1,它仍然是公鑰/私鑰密碼術使用最廣泛的標準。 任何足夠好的 JWT 庫都應支持它。 RSxxx 簽名也花費很少的 CPU 時間進行驗證(有助于確保在資源服務器上快速處理訪問令牌)。 推薦的 RSA 密鑰長度為 2048 位。

  • ESxxx 簽名算法使用橢圓曲線(EC)加密。 它們需要較短的密鑰,并且產生較小的簽名(相當于 RSA 強度)。 但是,EC 簽名有一個缺點:它們的驗證速度很慢

  • 新的 Edxxx 算法提供了最佳的簽名/驗證性能組合。 特別是通過 P-265 曲線簽名,比2048 位 RSA 高 62 倍,比 EC DSA 高 14 倍。

我們有 RSAECEdDSA 簽名的 JWT 的示例。

3、認證加密

  • 功能:機密性、完整性、認證

  • JOSE 格式:JSON Web Encryption(JWE)

  • 秘鑰類型:

    • Public / private key pair:
      • RSA
      • EC
      • OKP
    • Secret (shared) key
    • Password
  • 算法

  • 用例

    • 簽名和加密的ID令牌(OpenID Connect)
    • 簽名并加密的自包含訪問令牌(OAuth 2.0)
    • 加密的文檔和數據,具有完整性和真實性檢查
  • 備注

    • 保持私鑰和私鑰的安全!
    • 推薦的 RSA 密鑰大小為 2048 位

JOSE 通過以下方式提供加密:

  • 如果您想自己加密數據,請使用密鑰。 如果秘密密鑰是與其他方共享的(通過某種帶外方式),則他們也可以使用它來加密數據/解密密文。 請查看上表,了解可用的密鑰加密算法。

  • 收件人提供的公共密鑰(RSA,EC 或 OKP)。 例如,OpenID Connect 提供程序以可發現的 URL 以 JWK 格式發布其公共密鑰。 接收者然后可以使用其匹配的私鑰解密 JWT / JOSE 對象。 在不可能或不可行帶外通信的情況下,公鑰/私鑰密碼術是理想的選擇。

  • 如果您想使用可以記住的短語加密數據,則為密碼。

JOSE 中的加密始終是經過身份驗證的,這意味著密文的完整性受到保護,不會被篡改。 因此,經過身份驗證的加密使 HMAC JWT 嵌套在 JSON Web 加密(JWE)中變得多余。 僅使用 JWE 加密。

JWE 加密是一個“兩步”過程:

1、數據或內容始終使用 AES 密鑰(稱為內容加密密鑰或 CEK)進行加密,并且每個 JWT / JWE 對象都使用不同的 CEK。 Nimbus 庫將自動為您生成此 AES 密鑰,并且其長度將取決于 enc(加密方法)標頭參數(例如,"enc": "A128GCM" 將導致生成 128 位 AES 密鑰)。 除了可以選擇三種 AES 密鑰長度(128、198 和 256)之外,JOSE 還支持兩種內容加密模式:AxxxCBC-HSxxx 和 AxxxGCM。 通常,更廣泛地支持 AxxxCBC-HSxxx 模式。

2、第二步是使用輸入密鑰(即您提供的秘密密鑰,公共密鑰或密碼)對生成的 AES CEK 進行加密(也稱為包裝)。 這由 alg JWE 標頭參數指定。 如果要跳過第二步,直接提供 AES CEK,請選擇直接加密并指定 "alg": "dir" JWE 標頭參數。

示例 JWE 標頭,其中的內容在 GCM 模式下使用 128 位 AES 加密,而 AES CEK 本身使用公共 RSA 密鑰加密(使用 RSA OAEP 加密):

{
  "alg" : "RSA-OAEP",
  "enc" : "A128GCM"
}

您可以查看使用 RSA 公鑰加密 JWT 的示例

三、嵌套簽名和加密

可以對簽名的 JWT / JWS 對象進行附加加密,從而為數據提供完整性,真實性,不可否認性和機密性。

這是通過簡單的嵌套實現的(請參見示例):

1、JWT 用專用的 RSA,EC 或 OKP 密鑰簽名。
2、然后,簽名的 JWT 成為 JWE 對象的有效負載(純文本),該JWE對象使用接收者的公鑰(RSA,EC,OKP)或已在兩方之間共享的秘密密鑰進行加密。

處理嵌套的 JWT 向后工作:

1、使用適當的密鑰(RSA,EC 或 OKP 的私鑰或已建立的私鑰)解密 JWE 對象。
2、然后將提取的有效負載(純文本)解析為簽名的 JWT,并使用發行者的公鑰(RSA,EC 或 OKP)進行驗證。

Nimbus JOSE + JWT 庫提供了用于處理嵌套 JWT 的完整框架。

四、OpenID Connect 中的算法選擇

通過以下規則,您可以了解在給定客戶端注冊后哪些 ID 令牌算法可行:
1、具有 client_secret 的客戶端可以接收由 HMAC(其中 client_secret 充當 HMAC 秘密密鑰)或簽名(RSA,EC 或 EdDSA)保護的 ID 令牌。 為了驗證 RSA,EC 或 EdDSA 簽名的 ID 令牌,客戶端僅需要(從其 JWK 設置 URL 中)檢索 OpenID 提供程序的匹配公鑰。

2、帶有 client_secret 的客戶端也可以接收加密的 ID 令牌,其中 client_secret 用于從中導出秘密 AES 密鑰。

3、如果使用 HMAC,則要求的 client_secrets 必須足夠長以適合所需的密鑰長度。 例如,一個 256 位 client_secret 允許 HMAC 與 HS256 一起使用。

4、為了使客戶端能夠接收 RSAECDH 加密的 ID 令牌,它必須具備使用 OpenID 提供方注冊的 RSA,EC 或 OKP 公鑰。

5、OpenID Connect 還允許沒有 client_secret 的客戶端。 此類客戶端需要向 OpenID 提供程序注冊的 RSA,EC 或 OKP 公鑰,并使用該密鑰在令牌端點進行身份驗證(通過 JWT)。 如上所述,可以將 ID 令牌加密為該公共密鑰。

五、參考資料

(完)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。