【テクニカル・上級編】OpenID ConnectのIDトークン署名検証(JWS)のアルゴリズム固定 – アプリケーションセキュリティ & 安全な開発防御ガイド

JWT署名検証の「怠惰」が招く終焉:アルゴリズム固定という最後の防衛線

セキュリティの最前線に身を置く者として、私は数多の認証バイパスを調査してきた。その中で最も「美しくない」敗北の一つが、IDトークン(JWT/JWS)の署名検証におけるアルゴリズムの不適切な実装だ。

多くの開発者が利用するJWTライブラリは、汎用性を高めるために「ヘッダーで指定されたアルゴリズムを動的に読み取り、検証に使用する」という設計を採用している。この「柔軟性」こそが、地獄への入り口である。

なぜ alg: none やアルゴリズムのすり替えが成功するのか

攻撃者の視点に立てば、これは単純なパケット操作の範疇だ。

JWTは Header.Payload.Signature の3部構成だが、JWS仕様(RFC 7515)には、デバッグ用途や署名不要なケースを想定した alg: none という禁断の果実が存在する。もしアプリケーション側の検証ロジックが、以下のように実装されていたらどうなるか。

脆弱な実装例(絶対にしてはならない)
def verify_token(token):
# ヘッダーから alg を取得してそのまま信頼している
header = decode_header(token)
alg = header[‘alg’]
# この時点で攻撃者が alg=”none” を投げれば署名検証はスキップされる
return jwt.decode(token, options={“verify_signature”: False if alg == “none” else True})

このコードは、攻撃者が alg を none に書き換え、ペイロードを {"sub": "admin"} に改ざんしたトークンを送信するだけで、いとも簡単に管理者権限を奪取できる。

さらに深刻なのは、公開鍵暗号(RS256)を使用している環境で、攻撃者がアルゴリズムを対称鍵暗号(HS256)に書き換える攻撃だ。ライブラリが公開鍵を「HS256用の秘密鍵」として誤認して検証を行うと、多くの場合、署名の検証が通ってしまう。これはライブラリの設計ミスというよりは、「受信者が信頼すべきアルゴリズムを自ら選択する」という設計思想の崩壊に他ならない。

解決策:アルゴリズムのハードコーディングこそが唯一の正義

この脆弱性を根絶する唯一の手段は、コードの柔軟性を完全に破壊することだ。ライブラリのデコード関数に渡す設定で、許容するアルゴリズムを厳格に固定する。

堅牢な実装例(Python / PyJWTの例)
import jwt

def verify_token_securely(token, public_key):
try:
# アプリケーションが想定するアルゴリズムのみを許可する
# ここで動的に alg を取得してはならない
payload = jwt.decode(
token,
key=public_key,
algorithms=[“RS256”], # ここでアルゴリズムを固定する(ホワイトリスト化)
options={“require”: [“exp”, “iss”, “sub”]} # 必須クレームも強制する
)
return payload
except jwt.InvalidAlgorithmError:
# 許可外のアルゴリズムが指定された場合は即座に遮断しログ出力
logger.error(“不正な署名アルゴリズムが検知されました”)
raise

アーキテクトが見るべき「深淵」:耐量子時代の鍵管理

我々が今見据えるべきは、現在のRSAやECDSAが量子計算機によって無力化される未来だ。NISTが標準化を進める耐量子暗号(PQC)への移行期において、IDトークンの署名アルゴリズムもまた、RS256からEdDSAや将来的なPQC署名スキームへ移行する必要がある。

しかし、アルゴリズムを更新するたびにコードを書き換えるのは非効率だ。ここで重要なのが、「署名検証エンジン」をアプリケーションのビジネスロジックから切り離し、サイドカーやAPIゲートウェイ層に「検証専用のガードレイル」として配置する設計である。

  • 検証のオフロード: アプリケーション自体はJWTの「署名検証済み」データのみを信頼し、検証そのものはEnvoyやOPA(Open Policy Agent)等のポリシーエンジンに委託する。
  • ガードレイルの強制: ポリシーエンジン側で、許可されないアルゴリズムや期限切れのトークンをネットワークレベルで遮断する。

結論:プロトコルの仕様を信じるな

私が現場のエンジニアにいつも伝えているのは、「ライブラリのデフォルト設定を疑え」ということだ。ライブラリは開発者の利便性を優先して、時に致命的な脆弱性を許容する設定をデフォルトにすることがある。

JWSのヘッダーは、信頼の根拠(Trust Anchor)にはなり得ない。署名アルゴリズムはコードに刻み込み、外部からの入力によって決して変更させない。この「強固な固定」こそが、インジェクション攻撃や認証バイパスに対する、最も泥臭く、そして最も確実な防衛線である。

セキュリティとは、華麗なトリックを解くことではない。仕様の隙間を埋め、デフォルトの甘さを削ぎ落とすという、地道な作業の積み重ねだ。あなたのアプリケーションは、今日、本当に「署名済み」であると言い切れるか。今すぐ検証ロジックを再確認することを強く推奨する。

コメント

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