【実務・中級編】JWTの署名鍵ローテーション戦略と公開鍵公開エンドポイント(jwks_uri) – アプリケーションセキュリティ & 安全な開発防御ガイド

JWTの「鍵」を使い捨てろ:JWKSによる自動ローテーションの実装と、その裏側にある防衛哲学

こんにちは。現場の最前線でコードとログを追いかけているエンジニア諸君。

今日はJWT(JSON Web Token)の話をしよう。多くのプロジェクトで「HS256(共通鍵)」を使い、環境変数にハードコードされた文字列を使い回している姿を見るが、率直に言おう。それは時限爆弾を抱えて走っているのと同じだ。

万が一、開発者のPCやCI/CDのログから鍵が漏れた瞬間、攻撃者はあなたのアプリケーションの「神(管理者)」になれる。今日は、このリスクを根絶するための「鍵のローテーション」と、それを自動化する「JWKS(JSON Web Key Set)」のエンドポイント実装について、泥臭い実務の視点から解説する。

—

1. なぜ「静的な鍵」は死を招くのか(PoCの視点)

攻撃者がJWTを狙うとき、彼らは「脆弱性」を探すよりも先に「設定ミス」を探す。もしあなたが固定の鍵を使っていれば、攻撃者は以下のステップで侵入を試みる。

1. 鍵の抽出: バックアップファイル、Dockerイメージのレイヤー、あるいはGitHubのコミット履歴から鍵を抜き取る。
2. トークンの偽造: alg: HS256 を指定し、抜き取った鍵で署名した悪意あるJWTを作成する。
3. 権限昇格: sub(ユーザーID)を管理者のものに書き換え、サーバーに送りつける。サーバーは「正しい署名」である以上、これを正当なユーザーと見なす。

これを防ぐ唯一の解は、「鍵は漏れる前提で運用し、頻繁に無効化する(ローテーションする)」ことだ。

—

2. JWKSという「動的な信頼」の仕組み

JWKS(JSON Web Key Set)は、公開鍵をJSON形式で公開するための標準仕様だ。サーバーが今どの鍵を有効にしているかを動的にクライアント(あるいは検証用サービス)に伝えることができる。

  • メリット: 鍵を更新しても、クライアント側は jwks_uri を再取得するだけで追従できる。コードの修正も再デプロイも不要だ。

—

3. 実装サンプル:Python (FastAPI + PyJWT)

バックエンドでJWKSエンドポイントを実装する例だ。ここでは、鍵をメモリに保持し、一定期間でローテーションする設計を想定する。

import jwt
from datetime import datetime, timedelta
from cryptography.hazmat.primitives.asymmetric import rsa
from cryptography.hazmat.primitives import serialization

本来はDBやKMSから取得すべきだが、簡略化のため生成
private_key = rsa.generate_private_key(public_exponent=65537, key_size=2048)
public_key = private_key.public_key()

def get_jwks():
“””JWKS形式で公開鍵を返すエンドポイント用”””
public_numbers = public_key.public_numbers()
return {
“keys”: [{
“kty”: “RSA”,
“kid”: “my-key-id-001”, # 鍵の識別子(ローテーション時はここを変える)
“use”: “sig”,
“alg”: “RS256”,
“n”: format(public_numbers.n, ‘x’), # Base64URLエンコードが必要
“e”: format(public_numbers.e, ‘x’)
}]
}

検証側は、このJWKSを定期的にキャッシュしつつ、
トークンの header[‘kid’] と一致する鍵を使って検証を行う。

—

4. 運用のための「鉄の掟」

コードを書いて終わりではない。運用で事故らないための設定を共有しておく。

Nginxでのキャッシュ制御

jwks_uri は頻繁に叩かれる。サーバー負荷を減らすため、また鍵更新時に即座に反映させるために、適切なキャッシュヘッダーを付与すること。

location /.well-known/jwks.json {
# 鍵の更新を見越して、キャッシュは1時間程度に留める
add_header Cache-Control “public, max-age=3600”;
# 攻撃者からのスパムリクエストに備えてレートリミットをかける
limit_req zone=jwks_limit burst=5 nodelay;
}

AWS KMSとの連携

自前で鍵管理をするのは推奨しない。AWS KMS (Key Management Service) を使い、KMSが自動生成する公開鍵をJWKSとして公開するのが現在のベストプラクティスだ。KMSなら「鍵の自動ローテーション」をAWS側で完結できる。

—

最後に:セキュリティは「継続的な緊張感」

「いつか直す」は「一生直さない」と同義だ。今回紹介したJWKSの実装は、最初は面倒に感じるかもしれない。しかし、一度仕組み化してしまえば、鍵の漏洩という最悪のインシデントに対して「まあ、鍵を差し替えれば済む話だ」と冷静でいられる。

セキュリティとは、システムをガチガチに固めることではない。
「壊れたときに、いかに速く、安全に復旧できるか」という設計思想そのものだ。

明日から、君たちのプロダクトのJWT設定を見直してほしい。鍵をハードコードしている箇所を見つけたら、それが今日のリファクタリングのタスクだ。健闘を祈る。

コメント

タイトルとURLをコピーしました