這裡的 secret_key 是什麼“HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret_key)”

gongchengship發表於2024-10-21

在 JWT 的簽名過程中,secret_key 是用於生成並驗證簽名的一個金鑰。具體來說,secret_key 是伺服器端的一個私有金鑰,它用於確保 JWT 的簽名和資料的完整性,防止令牌被篡改。

1. secret_key 的作用

secret_key 是在簽名演算法(如 HMAC-SHA256)中使用的金鑰。在 JWT 的簽名部分,伺服器會使用這個金鑰來加密 JWT 的頭部和載荷,並生成簽名。具體過程如下:

  • 伺服器將 JWT 的頭部和載荷透過 Base64Url 編碼後拼接。
  • 伺服器使用預先定義的加密演算法(如 HMAC-SHA256)和 secret_key 計算出該拼接字串的簽名。
  • 最終生成的 JWT 是由三個部分構成:頭部、載荷、簽名。

只有擁有 secret_key 的伺服器才能生成或驗證這個簽名。如果有人嘗試篡改JWT的頭部或載荷,簽名就會不匹配,從而伺服器能夠檢測到。

2. secret_key 是從哪裡來的?

2.1 由伺服器生成和管理

secret_key 通常是由伺服器生成並管理的一個私密金鑰,它不會向客戶端或任何其他第三方公開。伺服器透過這個金鑰來保證 JWT 的安全性。不同的應用程式會根據安全需求和架構選擇不同的方式生成和管理 secret_key

  • 靜態金鑰:通常在配置檔案或環境變數中硬編碼或配置。比如,使用常量金鑰用於簡單應用場景。

  • 動態金鑰:為了增強安全性,一些應用會動態生成和輪換金鑰。動態金鑰可以透過加密服務(如 AWS Key Management Service (KMS))生成。

  • 金鑰管理服務:在大規模生產環境中,企業通常使用諸如 Amazon KMS、Google Cloud KMS 或者 HashiCorp Vault 等專門的金鑰管理服務,確保金鑰的安全儲存和定期輪換。

2.2 如何選擇和配置 secret_key

配置 secret_key 時,以下幾點需要注意:

  • 隨機性和複雜性secret_key 應該是足夠長且隨機的字串,以避免暴力破解。使用弱密碼或易猜的金鑰會降低JWT的安全性。

  • 儲存安全性secret_key 需要安全儲存,通常透過環境變數或者安全配置檔案進行管理,避免暴露在原始碼中。

  • 定期輪換:在敏感應用中,金鑰應定期進行輪換,這可以避免某些攻擊型別(如長期暴露的金鑰被破解)。

2.3 多伺服器環境下的 secret_key

在分散式系統或微服務架構中,通常有多個伺服器例項共同服務於請求。在這種情況下,所有的伺服器例項需要共享同一個 secret_key,這樣任意一臺伺服器生成的 JWT 令牌都可以被其他伺服器驗證。

為了解決這個問題,通常有以下幾種方式:

  • 共享配置:所有的伺服器例項都透過共享配置檔案或者環境變數獲取相同的 secret_key

  • 集中管理金鑰服務:使用金鑰管理服務來為所有伺服器提供統一的金鑰服務,確保所有例項能夠獲得相同的金鑰。

3. 如何驗證 JWT 簽名

當伺服器收到帶有 JWT 的請求時,會使用相同的 secret_key 來驗證簽名。驗證過程如下:

  1. 伺服器從JWT中分離出頭部和載荷,並重新計算它們的簽名。
  2. 使用伺服器儲存的 secret_key 和相同的加密演算法(如 HMAC-SHA256),重新計算JWT的簽名。
  3. 將計算出的簽名與收到的JWT中的簽名進行比較。如果簽名匹配,則證明JWT沒有被篡改。

4. JWT 的簽名演算法與金鑰型別

JWT 支援多種不同的簽名演算法,每種演算法對金鑰有不同的要求:

  • 對稱加密演算法(如 HMAC-SHA256):客戶端和伺服器共享同一個 secret_key,它既用於生成簽名,也用於驗證簽名。HMAC-SHA256 是 JWT 中常見的一種對稱簽名演算法。

  • 非對稱加密演算法(如 RSA 或 ECDSA):這類演算法使用一對金鑰(公鑰和私鑰)。伺服器使用私鑰簽名,客戶端或伺服器可以使用公鑰驗證簽名。這種方式更適合於分散式系統,因為客戶端不需要知道伺服器的私鑰。

    對於非對稱加密,伺服器生成JWT時使用的是私鑰,而驗證JWT時,客戶端或其他服務使用伺服器的公鑰。

5. 示例:生成和驗證 JWT 簽名

生成 JWT 簽名(以 HMAC-SHA256 為例):

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.util.Base64;

public class JWTExample {
    public static void main(String[] args) throws Exception {
        // Header 和 Payload
        String header = "{\"alg\":\"HS256\",\"typ\":\"JWT\"}";
        String payload = "{\"sub\":\"1234567890\",\"name\":\"John Doe\",\"iat\":1516239022}";

        // Base64Url 編碼
        String encodedHeader = Base64.getUrlEncoder().withoutPadding().encodeToString(header.getBytes());
        String encodedPayload = Base64.getUrlEncoder().withoutPadding().encodeToString(payload.getBytes());

        // secret_key 用於簽名
        String secretKey = "your-secret-key";
        
        // HMAC-SHA256 簽名
        Mac hmacSHA256 = Mac.getInstance("HmacSHA256");
        SecretKeySpec secretKeySpec = new SecretKeySpec(secretKey.getBytes(), "HmacSHA256");
        hmacSHA256.init(secretKeySpec);

        // 簽名生成
        String data = encodedHeader + "." + encodedPayload;
        byte[] signatureBytes = hmacSHA256.doFinal(data.getBytes());
        String signature = Base64.getUrlEncoder().withoutPadding().encodeToString(signatureBytes);

        // 最終的 JWT
        String jwt = encodedHeader + "." + encodedPayload + "." + signature;
        System.out.println("JWT: " + jwt);
    }
}

驗證 JWT 簽名:

驗證簽名時,伺服器使用同樣的 secret_key 和 HMAC-SHA256 演算法,計算JWT的頭部和載荷部分的簽名,並與接收到的簽名進行比較。

6. 總結

secret_key 是JWT生成和驗證中至關重要的安全要素。在使用對稱加密演算法(如HMAC-SHA256)時,secret_key 是用於生成和驗證簽名的金鑰,確保JWT資料的完整性。它通常由伺服器生成和安全管理,並且不會公開給客戶端。透過使用強密碼策略和安全管理機制,可以確保 secret_key 不被暴露,從而保證JWT的安全性。

相關文章