OpenID Connect(OIDC)を安全に実装・運用するための推奨事項をまとめたもの。主に RP(Relying Party / クライアント)側の実装者を想定し、OP(OpenID Provider / 認可サーバー)側の設定についても触れる。


目次

  1. 前提:OIDC と OAuth 2.0 の関係
  2. フローの選択
  3. 認可リクエストのベストプラクティス
  4. リダイレクト URI
  5. ID Token の検証
  6. トークンの扱い
  7. クライアント認証
  8. ディスカバリーと鍵管理
  9. ログアウト
  10. スコープとクレームの最小化
  11. OP(認可サーバー)側の設定チェックリスト
  12. RP 実装チェックリスト
  13. よくあるアンチパターン

1. 前提:OIDC と OAuth 2.0 の関係

項目OAuth 2.0OpenID Connect
目的認可(API へのアクセス権の委譲)認証(ユーザーが誰かの確認)
主な成果物Access TokenID Token(JWT)+ Access Token
ユーザー情報規定なしUserInfo エンドポイント、標準クレーム
  • Access Token をログインの証明として使わない。 ユーザーの認証結果は必ず ID Token で確認する。
  • OIDC は OAuth 2.0 の上に乗っているため、OAuth 2.0 のセキュリティ対策(RFC 9700)がそのまま適用される。

2. フローの選択

推奨:Authorization Code Flow + PKCE

  • すべてのクライアント種別(Web サーバー、SPA、ネイティブアプリ)で Authorization Code Flow を使う。
  • PKCE(RFC 7636)は機密クライアントでも必須扱いにする。認可コードの横取り・注入攻撃を防げる。
  • code_challenge_method は S256 を使う(plain は使わない)。

非推奨・使用禁止

フロー状態理由
Implicit Flow(response_type=token / id_token token)使わないトークンが URL フラグメントに露出、リプレイ・漏洩リスク
Resource Owner Password Credentials使わないクライアントがパスワードを直接扱う、MFA と相性が悪い
Hybrid Flow特別な理由がなければ不要複雑化に見合うメリットが少ない。Code + PKCE で十分

用途別の補足

  • マシン間通信(ユーザー不在):Client Credentials Grant(これは OIDC ではなく OAuth 2.0)。
  • 入力制約デバイス(TV など):Device Authorization Grant(RFC 8628)。
  • 高セキュリティ用途(金融・医療など):FAPI 2.0 Security Profile への準拠を検討する。

3. 認可リクエストのベストプラクティス

必須パラメータの正しい使い方

パラメータ推奨
response_typecode
scopeopenid を必ず含める。必要最小限のスコープのみ要求
redirect_uri事前登録した値と完全一致させる
state推測不能なランダム値。CSRF 対策。セッションに紐付けて検証
nonce推測不能なランダム値。ID Token のリプレイ対策。ID Token 内の値と照合
code_challenge / code_challenge_methodPKCE。S256
  • state と nonce は最低 128 bit 以上のエントロピーを持つ暗号論的乱数で生成する。
  • PKCE を使っていても state(またはそれに相当する CSRF 対策)と nonce は省略しない。

Pushed Authorization Requests(PAR, RFC 9126)

  • 認可リクエストのパラメータをフロントチャネル(ブラウザ URL)ではなく、バックチャネルで OP に事前送信する。
  • パラメータの改ざん・漏洩を防ぎ、URL 長の問題も解消できる。OP が対応しているなら利用を推奨。FAPI 2.0 では必須。

Mix-Up 攻撃対策

  • 複数の OP と連携する RP では、認可レスポンスの iss パラメータ(RFC 9207) を検証し、リクエストを送った OP からの応答であることを確認する。
  • OP ごとに異なる redirect_uri を使うのも有効。

4. リダイレクト URI

  • 完全一致で照合する(ワイルドカード・部分一致・パターンマッチは使わない)。
  • 本番では HTTPS 必須。
  • オープンリダイレクトを持つページを redirect_uri にしない。
  • ネイティブアプリ(RFC 8252):
    • プライベートスキーム(com.example.app:/callback、逆ドメイン形式)か Claimed HTTPS スキーム(Universal Links / App Links)を使う。後者が望ましい。
    • ループバック(http://127.0.0.1:{port}/)はポート番号を可変として許容する。localhost ではなく IP リテラルを使う。
    • 埋め込み WebView は使わず、システムブラウザ(ASWebAuthenticationSession / Custom Tabs)を使う。

5. ID Token の検証

ID Token は必ずすべて検証してから使う。ライブラリ任せにする場合も、以下が行われていることを確認する。

  1. 署名の検証
    • OP の jwks_uri から公開鍵を取得し、kid で鍵を選択。
    • alg は許可リストで固定する(例:RS256, PS256, ES256)。none は拒否。
    • ヘッダーの alg を盲目的に信用しない(アルゴリズム混同攻撃対策)。
  2. iss:期待する OP の Issuer Identifier と完全一致。
  3. aud:自分の client_id が含まれていること。複数含まれる場合は azp も確認。
  4. exp:期限切れでないこと(時刻ずれの許容は数分程度に留める)。
  5. iat:極端に古い/未来の値でないこと。
  6. nonce:リクエスト時に送った値と一致すること。
  7. auth_time / acr / amr:max_age や特定の認証強度(MFA など)を要求した場合は検証する。

ユーザーの識別

  • ユーザーの一意識別には iss + sub の組み合わせを使う。
  • email をキーにしない。 メールアドレスは変更・再利用され得るし、email_verified が false の場合もある。
  • アカウントを email で自動紐付けする場合は、email_verified=true かつ信頼できる OP に限定する。

6. トークンの扱い

保存場所

クライアント種別推奨
サーバーサイド Web アプリトークンはサーバー側に保存。ブラウザにはセッション Cookie のみ
SPABFF(Backend for Frontend)パターンを推奨。トークンをブラウザ JS に渡さない
ネイティブアプリOS のセキュアストレージ(Keychain / Keystore)
  • SPA で BFF が使えない場合も、localStorage への保存は XSS 時に窃取されるため避け、メモリ保持を基本とする。
  • セッション Cookie は Secure、HttpOnly、SameSite=Lax 以上、可能なら __Host- プレフィックスを付ける。

有効期限とリフレッシュ

  • Access Token は短命(数分〜1時間程度)にする。
  • Refresh Token は以下のいずれかで保護する:
    • 公開クライアントでは Refresh Token Rotation(使用ごとに新しいトークンを発行し、旧トークンの再利用を検知したら一連のトークンを失効)。
    • または 送信者制約(Sender-Constrained)トークン(後述)。
  • Refresh Token には絶対的な有効期限とアイドルタイムアウトを設定する。

送信者制約トークン

トークン漏洩時の悪用を防ぐため、トークンを特定のクライアント鍵に紐付ける。

  • DPoP(RFC 9449):アプリケーション層で鍵を証明。SPA・ネイティブでも使いやすい。
  • mTLS(RFC 8705):クライアント証明書に紐付け。サーバー間通信向け。

その他

  • トークンを URL クエリ・ログ・エラーメッセージに出力しない。
  • Access Token の中身を RP 側で解釈しない(Access Token はリソースサーバー向け。RP にとっては不透明な文字列として扱う)。

7. クライアント認証

  • 機密クライアントでは、共有シークレット(client_secret_basic / client_secret_post)より非対称鍵による方式を推奨:
    • private_key_jwt
    • tls_client_auth / self_signed_tls_client_auth(mTLS)
  • client_secret を使う場合は十分な長さのランダム値とし、定期的にローテーションする。
  • 公開クライアント(SPA・ネイティブ)にはシークレットを埋め込まない(秘匿できないため意味がない)。

8. ディスカバリーと鍵管理

  • OP のメタデータは /.well-known/openid-configuration から取得し、エンドポイントをハードコードしない。
  • メタデータ内の issuer が、取得元の Issuer と一致することを確認する。
  • JWKS はキャッシュしつつ、未知の kid が来たら再取得する(鍵ローテーション対応)。ただし再取得の頻度は制限して DoS を防ぐ。
  • OP 側は署名鍵を定期的にローテーションし、新旧の鍵を一定期間並行公開する。

9. ログアウト

  • 単にローカルセッションを消すだけでは OP のセッションは残る。要件に応じて以下を組み合わせる:
    • RP-Initiated Logout:end_session_endpoint に id_token_hint と post_logout_redirect_uri(事前登録済み)を付けてリダイレクト。
    • Back-Channel Logout:OP からサーバー間で Logout Token を受け取り、該当セッションを破棄。サードパーティ Cookie 制限の影響を受けないため推奨。
    • Front-Channel Logout:iframe ベースのため、サードパーティ Cookie 制限で動作しない場合が多い。新規採用は慎重に。
  • Logout Token も ID Token と同様に署名・iss・aud・iat・jti(リプレイ対策)を検証し、nonce が含まれていないことを確認する。

10. スコープとクレームの最小化

  • 必要なスコープ・クレームだけを要求する(profile や email を惰性で要求しない)。
  • 取得した個人情報は必要な期間だけ保持し、ログに出力しない。
  • 細かい要件がある場合は claims パラメータで個別に要求する。

11. OP(認可サーバー)側の設定チェックリスト

  • Implicit Flow・ROPC を無効化している
  • PKCE を必須にしている(S256 のみ許可)
  • redirect_uri を完全一致で照合している
  • 認可コードは短命(推奨 1 分以内)かつ一回限り。再利用時は発行済みトークンを失効させる
  • 認可コードを、発行先クライアント・redirect_uri・PKCE チャレンジに紐付けている
  • 認可レスポンスに iss を含めている(RFC 9207)
  • 公開クライアントの Refresh Token に Rotation または送信者制約を適用している
  • PAR に対応している(可能なら必須化)
  • 署名アルゴリズムの許可リストを設定し、none を拒否している
  • 署名鍵のローテーション手順がある
  • トークン失効(RFC 7009)・イントロスペクション(RFC 7662)を提供している
  • ログイン試行に対するレート制限・異常検知がある

12. RP 実装チェックリスト

  • Authorization Code Flow + PKCE(S256)を使っている
  • state と nonce を暗号論的乱数で生成し、検証している
  • ID Token の署名・iss・aud・exp・nonce をすべて検証している
  • ユーザーを iss + sub で識別している(email ではなく)
  • 複数 OP 連携時に iss レスポンスパラメータを検証している
  • トークンをブラウザ JS に露出させていない(SPA は BFF を検討)
  • セッション Cookie に Secure / HttpOnly / SameSite を付与している
  • ネイティブアプリでは埋め込み WebView ではなくシステムブラウザを使っている
  • 機密クライアントは private_key_jwt または mTLS で認証している
  • トークンや個人情報をログに出力していない
  • ログアウト時に OP 側セッションも考慮している
  • 自前実装ではなく、OpenID Foundation の認定を受けた、またはよくメンテナンスされたライブラリを使っている

13. よくあるアンチパターン

アンチパターン問題対策
Access Token でログイン判定別クライアント向けトークンでなりすまされるID Token を検証する
ID Token を API 呼び出しの Bearer に使うID Token は RP 向け。aud が API と一致しないAccess Token を使う
email でユーザーを紐付け未検証メール・再利用メールによる乗っ取りiss + sub を使う
redirect_uri にワイルドカード認可コードの窃取完全一致で登録
state を固定値や省略ログイン CSRFランダム値をセッションに紐付けて検証
JWT のデコードだけして署名検証しない偽造トークンを受け入れる必ず署名を検証
SPA で localStorage にトークン保存XSS で窃取BFF パターン / メモリ保持
認可・認証処理を自前実装検証漏れ・脆弱性実績あるライブラリを使う

参考仕様

0件のページ