【実務・中級編】OpenID Connect (OIDC)におけるIDトークンの検証不備と署名アルゴリズムの強制 – アプリケーションセキュリティ & 安全な開発防御ガイド

OIDCのIDトークン検証:なぜ「none」を許した瞬間にシステムは終わるのか

現場でコードレビューをしていると、未だに「IDトークンの検証処理」でヒヤリとする実装を見かける。特にOpenID Connect (OIDC)を導入しているシステムにおいて、署名検証を甘く見ることは、玄関の鍵をわざわざ開けて「どうぞご自由にお入りください」と泥棒を招き入れるのと同じだ。

今日は、攻撃者がIDトークンの署名検証不備をどう突くのか、そして我々エンジニアがなぜ「alg: none」という悪魔の仕様をコードから排除しなければならないのか、実戦的な視点で深掘りしていく。

—

1. 攻撃者が狙う「署名検証の盲点」

IDトークン(JWT)は、Header.Payload.Signature という構造をしている。このうち、Signatureは「このトークンは認可サーバーが発行した正当なものだ」という証明書だ。

攻撃者が狙うのは、この証明を無効化する以下の2つの手法だ。

手法A:alg: none の悪用

ライブラリの仕様や設定ミスにより、JWTのヘッダーにある alg (アルゴリズム) を none に書き換える。検証ロジックが「アルゴリズムが指定されていないなら検証不要」と判断すれば、攻撃者は好きな sub (ユーザーID) を書き込んだ偽トークンを送り込み、誰にでもなりすませる。

手法B:アルゴリズムの強制不備(RS256 vs HS256)

ここが最も闇が深い。公開鍵暗号方式(RS256)を期待しているのに、共通鍵暗号方式(HS256)として検証してしまう脆弱性だ。攻撃者は、公開鍵を「鍵」として使い、HS256で署名を再生成する。検証ライブラリが「鍵の種類」をチェックせずに署名を検証してしまえば、いとも簡単に権限昇格が成立する。

—

2. 実践:絶対にやってはいけない実装と、正しい実装

脆弱なコード例(Python / PyJWT)

以下のコードは、セキュリティを自ら放棄している最悪のパターンだ。

【危険】アルゴリズムを指定せず、検証をバイパスする可能性が高い実装
import jwt

def decode_token_bad(token):
# 警告:algorithmsを指定しないと、攻撃者が指定したアルゴリズムで検証されてしまう
# noneアルゴリズムが有効なライブラリだと、署名なしで通ってしまう
payload = jwt.decode(token, options={“verify_signature”: False})
return payload

セキュアな実装(Python / PyJWT)

検証ライブラリは、「使用するアルゴリズムを明示的に強制する」のが鉄則だ。

import jwt

def decode_token_secure(token, public_key):
try:
# 1. 使用するアルゴリズムを明示的に指定(RS256など)
# 2. 署名検証は必ずTrueに(デフォルトだが明示すること)
# 3. 期限(exp)の検証も必須
payload = jwt.decode(
token,
public_key,
algorithms=[“RS256”],
options={“require”: [“exp”, “iat”, “nbf”]}
)
return payload
except jwt.ExpiredSignatureError:
# トークン期限切れのハンドリング
raise Exception(“トークンが期限切れです”)
except jwt.InvalidTokenError:
# 署名不一致や不正な形式のハンドリング
raise Exception(“不正なトークンです”)

—

3. インフラレベルでの防衛:WAFとゲートウェイの役割

アプリケーション層だけで完璧な防御を求めるのは酷だ。特に大規模なマイクロサービス構成では、API Gateway側で検証を完結させるのがベストプラクティスだ。

NginxやKong、AWS API GatewayのCognitoオーソライザーを使用する場合、署名検証はフロントで弾く。

Nginxの設定例(JWT認証モジュール利用):

auth_jwt “OIDC Realm”;
auth_jwt_key_file conf/oidc_public_key.pem;
使用可能なアルゴリズムを強制的に制限
auth_jwt_alg RS256;

このように、アプリケーションにリクエストが届く前に「署名が正しくない」「アルゴリズムが禁止されている」ものは全て401/403で遮断する。これが多層防御の基本だ。

—

4. チーフからの教訓:ライブラリ選定の基準

最後に、ライブラリを選ぶ際は以下のチェックリストを通すこと。

1. デフォルトで none を許可していないか?(許可しているなら即座に排除するか、設定で無効化する)
2. アルゴリズムの強制指定が容易か?
3. 公開鍵のローテーション(JWKSの自動取得)に対応しているか?(ハードコードされた鍵は即座に陳腐化する)

「便利だから」「動くから」という理由で古いライブラリを使い続けるのは、セキュリティエンジニアとして一番やってはいけないことだ。IDトークンはシステムの「身分証明書」。これを偽造されるということは、あなたのシステムには「誰でも入れる裏口」があるのと同じだ。

今日からすぐに、全リポジトリで alg の指定を確認してほしい。もし none を許容するコードを見つけたら、それは仕様ではなく「バグ」としてチケットを切るべきだ。

セキュリティは、派手なハッキングを防ぐことではなく、こうした地味な設定の積み重ねで担保される。現場のエンジニア諸君、足元をしっかり固めていこう。

コメント

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