Cloudflare API Shield 支援 HS256 了:對稱 JWT 驗證怎麼設定
Cloudflare API Shield 的 JWT validation 在 2026 年 8 月 25 日加入對稱金鑰支援,現在可以驗證使用 HS256、HS384 或 HS512 簽署的 token。這適合由 issuer 和 validator 共用 HMAC secret 的 API,但也代表 secret 的產生、交付與輪替都要由你自己維護。
直接答案是:在 token configuration 放入 kty: "oct" 的 HMAC JWK,讓 alg 和 JWT header 的 alg 一致,讓 kid 能對應到正在使用的 key;接著用規則決定無效或缺少 JWT 的請求要 log 還是 block。 API Shield 只負責驗證簽章與 claims,不會替你設計完整的 authorization policy。
對稱與非對稱 JWT 的差異
| 驗證方式 | Cloudflare 需要什麼 | 適合的情境 | 主要風險 |
|---|---|---|---|
| RSA/EC 非對稱 | issuer 發布的 public JWKS | 多個驗證端、希望只公開公鑰 | JWKS 更新與 key cache |
| HMAC 對稱 | 和 issuer 共用的 secret | 服務數量有限、現有 token 使用 HS 系列 | secret 任何一方外洩都能簽發 token |
Cloudflare 公告表示,對稱 credential 不會以明文儲存,API 回應也不會回傳 credential;但 issuer 端仍必須保管原始 secret。這不是「可以把 secret 放在 repository」的理由,也不會阻止拿到 secret 的人偽造合法 JWT。
先準備符合 JWT header 的 HMAC JWK
API 的 credentials.keys 使用 JWK 形式。下面是結構示例,k 只放示意值,不能把真實 secret 寫進文章、issue 或 shell history:
{ "credentials": { "keys": [ { "kty": "oct", "alg": "HS256", "kid": "api-2026-08", "k": "<base64url-secret>" } ] }, "title": "internal-api-hmac", "description": "JWT verification for internal API", "token_sources": [ "http.request.headers[\"authorization\"][0]" ], "token_type": "JWT"}這裡的四個欄位各自扮演不同角色:
kty: "oct"表示對稱 key;alg必須是HS256、HS384或HS512。kid要和 issuer 放在 JWT header 的 key ID 對上,不能只更新 Cloudflare 端的 secret 字串。k是建立或更新設定時提供的對稱 key material;它不應出現在 log、Terraform plan 輸出或 PR diff。token_sources決定 Cloudflare 從哪個 header 或 cookie 取 token。若使用Authorization,請確認 issuer 與 client 的格式一致。
不要把 alg 當成可由請求者任意選擇的安全開關。驗證設定應固定允許的算法,並在測試中確認使用錯誤算法、錯誤 kid、過期與錯誤簽章的 token 都會得到預期結果。
用 API 建立 token configuration
Cloudflare API 的建立 endpoint 是 zone scoped。示例只展示結構,不包含真實 credential:
curl --request POST \ --url "https://api.cloudflare.com/client/v4/zones/$ZONE_ID/token_validation/config" \ --header "Authorization: Bearer $CLOUDFLARE_API_TOKEN" \ --header "Content-Type: application/json" \ --data @token-config.jsontoken-config.json 應由 secret manager 或受控部署流程產生;不要先把檔案加入 Git,再用 .gitignore 補救。部署後保存回應中的 configuration ID 與非敏感 metadata,之後規則要用到它,但不要期待 GET 回應能讓你重新取回 HMAC secret。
Dashboard 的路徑則是 Security Settings → API abuse → Token configurations → Configure tokens。先在低風險 hostname 或測試端點驗證,再把同一套設定帶到 production;不要用 production token 當作第一個測試輸入。
Token configuration 和 enforcement rule 是兩件事
Cloudflare 的流程分成「找到並驗證 JWT」和「依結果採取動作」兩部分。只有建立 configuration,不等於無效 token 已經被阻擋。
如果需要依 claims 或其他訊號做 zone-wide policy,優先考慮 WAF custom rules;如果只想套用到 Endpoint Management 的特定 operation,才使用 JWT validation rules。可以用已驗證的 claim 寫條件,例如:
lookup_json_string( http.request.jwt.claims["<TOKEN_CONFIGURATION_ID>"][0], "role") eq "admin"在規則中還要明確決定「缺少 JWT」的行為:
| 行為 | 代表什麼 | 適合情境 |
|---|---|---|
| Ignore | 沒有 JWT 的請求不因缺少 token 被視為不合規;若有 token 仍會驗證 | 公開與登入後流量共用 endpoint |
| Mark as non-compliant | 預期每個選定端點都應有 JWT | 純受保護的 API 路徑 |
先用 log 觀察合法 client、過期 token、錯誤 kid 和缺少 header 的比例,再切換 block。若規則直接 block,會很難分辨是 JWT 內容錯誤、token source 選錯,還是 CORS preflight 被誤判。
輪替時同時處理 kid 與 issuer
HMAC 輪替不是只在 Cloudflare 貼上新 secret。比較穩妥的順序是:
- 先建立新的 key material 與新的
kid,在受控的 token configuration 中讓驗證端同時認得舊、新 key。 - 更新 issuer,讓新簽發的 JWT 使用新的
kid;保留舊 key 直到所有 client 與 token TTL 都跨過切換窗口。 - 用實際 API 請求確認新 token 通過、舊 token 在預期的寬限期內仍符合策略,並觀察 Cloudflare log。
- 到期後移除舊 key,將 secret manager、部署紀錄與回復文件一起更新。
如果 API 更新 endpoint 要求提交完整的 key set,就不要用只包含新 key 的 payload 意外刪掉仍在使用的舊 key。先讀取該 endpoint 的 PUT/PATCH 語意,在 staging 做一次輪替,再安排 production 窗口。這種遷移和 Cloudflare Access Service Token 的 Grace Period 輪替相似:兩者都需要先切換使用端,再讓舊 credential 失效,但 API Shield 的 key matching 還多了一層 alg 和 kid 對應。
別忘了 CORS 和 token 位置限制
Cloudflare 文件特別提醒,瀏覽器的 CORS OPTIONS preflight 通常不帶 authentication header 或 cookie。如果把所有 OPTIONS 都套用「缺少 JWT 就 block」,前端真正的 GET 或 POST 可能永遠到不了 API;公開 API 的規則可視情況加入 or http.request.method eq "OPTIONS"。
此外,JWT validation 只處理 request header 或 cookie 中的 token,不處理放在 POST body 的 JWT。若你的 client 把 token 放在 body,應先重新評估 API contract,不要只改 token source 期待 Cloudflare 自動找到它。
結論是:HS256 支援讓使用 HMAC 的 API 可以直接接上 API Shield,但也把共享 secret 的治理責任帶進來。先固定 JWK 的 alg、kid 和 token source,再用 log-to-block 的順序驗證規則,最後用可觀察的雙 key 窗口完成輪替,才不會把一次小改動變成全站驗證中斷。
常見問題
API Shield 可以直接把 HMAC secret 讀回來嗎?
不行。Cloudflare 表示不會以明文儲存對稱 credential,API 回應也不會包含 credential。原始 secret 應保留在 issuer 與受控的 secret manager,遺失時要依輪替流程建立新 key。
JWT header 的 kid 不同,但 secret 一樣,可以通過嗎?
不能假設可以。Cloudflare 會依設定的 key identity 和算法驗證,kid 是 key matching 的一部分。若要切換 key,應讓 issuer 和 token configuration 同時使用相同的 kid。
為什麼 token configuration 建立後,錯誤 JWT 還沒有被擋下來?
因為 configuration 負責找到和驗證 JWT,規則才負責對不合規結果採取 log 或 block。請另外檢查 rule selector、缺少 JWT 的處理方式與 CORS OPTIONS 例外。
參考資料:
Cloudflare Changelog:Symmetric key support for JWT validation
回報錯字、失效連結,或告訴我你想看的延伸主題。