本文翻譯自 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、數字簽名
功能:完整性、認證、不可抵賴性
JOSE 格式:JSON Web Signature(JWS)
-
秘鑰類型:公鑰/私鑰對
- RSA
- EC
- OKP
-
算法
-
RSA signature with PKCS #1 and SHA-2
- RS256
- RS384
- RS512
-
- PS256
- PS384
- PS512
-
- ES256
- ES384
- ES512
-
Edwards-curve DSA signature with SHA-2
- Ed25519
- Ed448
-
-
用例
- ID tokens (OpenID Connect)
- Self-contained access tokens (OAuth 2.0)
- 在域之間傳遞安全性斷言和令牌
- 需要必須由其他人驗證數據的完整性和真實性的場景
-
備注
- 私鑰一定要保密!
- 推薦的 RSA 密鑰大小為 2048 位
- EdDSA 簽名提供最佳性能
數字簽名適用于發行令牌、聲明、斷言和文檔,且這些文檔的完整性和真實性必須由其他各方進行驗證的場景。
使用示例:
- 由 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 倍。
我們有 RSA,EC 和 EdDSA 簽名的 JWT 的示例。
3、認證加密
功能:機密性、完整性、認證
JOSE 格式:JSON Web Encryption(JWE)
-
秘鑰類型:
- Public / private key pair:
- RSA
- EC
- OKP
- Secret (shared) key
- Password
- Public / private key pair:
-
算法
-
公鑰/私鑰加密
- RSA
-
RSA OAEP
- RSA-OAEP
- RSA-OAEP-256
- RSA PKCS #1
-
RSA OAEP
- EC
- RSA
-
秘密(共享)密鑰加密
-
Direct AES encryption
- dir
-
AES key wrap
- A128KW
- A192KW
- A256KW
-
AES GCM key encryption
- A128GCMKW
- A192GCMKW
- A256GCMKW
-
Direct AES encryption
-
基于密碼加密
-
PBES2
- PBES2-HS256+A128KW
- PBES2-HS384+A192KW
- PBES2-HS512+A256KW
-
PBES2
-
-
用例
- 簽名和加密的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、為了使客戶端能夠接收 RSA 或 ECDH 加密的 ID 令牌,它必須具備使用 OpenID 提供方注冊的 RSA,EC 或 OKP 公鑰。
5、OpenID Connect 還允許沒有 client_secret 的客戶端。 此類客戶端需要向 OpenID 提供程序注冊的 RSA,EC 或 OKP 公鑰,并使用該密鑰在令牌端點進行身份驗證(通過 JWT)。 如上所述,可以將 ID 令牌加密為該公共密鑰。
五、參考資料
(完)