ガイドSC

SC科目B(午後)のOpenID ConnectとID Token検証

公開: 2026-09-25更新: 2026-09-26
OpenID ConnectとOAuth 2.0の違い、ID Token、JWT、nonce、iss・aud・exp、署名検証を一つのログイン事例で解説。異常ログと鍵更新も学ぶ。

OpenID Connect(OIDC)はOAuth 2.0の上に、利用者を認証した結果をClientへ伝える仕組みです。科目Bでは、認可コード交換の成功だけでログインを成立させていないか、ID Tokenの署名とclaimを誰がどの値と照合したかが判断点になります。この記事では請求書サービスへのログインを一つの事例に、JWT、nonce、iss・aud・exp、署名検証と失敗ログをつなげます。

読み順は、①OAuthとの役割の違い、②認可コードを使ったOIDCログイン、③ID Tokenの構造とclaim、④署名・claim検証、⑤異常ログと鍵更新、⑥記述演習です。billing.example、id.partner.example、時刻、ID、鍵識別子、ログはすべて説明用の架空例です。JWTの例はBase64urlデコード後の表示であり、実際に使える署名済みトークンではありません。

1. OAuth 2.0の委譲とOIDCのログインを分ける

OAuth 2.0でClientが受け取るAccess Tokenは、Resource ServerのAPIを使うための権限です。Access Tokenの取得成功だけで、ClientがどのEnd-Userを認証したかは表せません。OIDCは認可要求にopenid scopeを加え、OpenID Provider(OP)が認証したEnd-UserについてID TokenをClientへ返します。ClientはOIDCではRelying Party(RP)とも呼ばれます。

  • End-User:経理担当者A。OPで認証され、billing.exampleへログインしたい利用者です。

  • RP/Client:billing.exampleのサーバ。ID Tokenを検証し、Aをローカル利用者ID 41へ対応付けてアプリ内セッションを作ります。内部利用者IDは整数です。

  • OP/認可サーバ:id.partner.example。Aを認証し、ID TokenとAPI用Access Tokenを発行します。

  • UserInfo Endpoint:OPが提供する利用者情報のAPI。必要ならAccess Tokenで呼びますが、返ったsubをID Tokenのsubと照合します。

この事例のRPはサーバ上でClient認証情報とPKCEのverifierを保管できます。ブラウザには認可コードとstateが返り、RPのサーバがToken Endpointでトークン交換を行います。ID TokenをAPIへBearer Tokenとして送ったり、Access TokenをID Tokenの代わりにログイン判定へ使ったりしません。

次の比較図は、同じToken Endpointから返る二種類の値を整理します。図の検証主体と宛先の違いを先に押さえると、audの読み違いを避けられます。

ID TokenとAccess Tokenの役割架空の請求書サービス。ID TokenはRPのログイン判定、Access Tokenは対象APIへの権限提示に使う。ID TokenAccess Token受け手RPResource Server主な目的利用者の認証APIへのアクセス宛先audRPのclient_id対象APIなど形式JWT不透明値もある
ID TokenとAccess Tokenの役割

架空の請求書サービス。ID TokenはRPのログイン判定、Access Tokenは対象APIへの権限提示に使う。

ID Tokenのaudがbilling-webなら、そのTokenはbilling.exampleのRP向けです。ファイルAPI向けのAccess Tokenのaudやscopeとは別です。Access Tokenの形式や検証方法はAPIの設計に依存しますが、OIDCのID TokenはJWTで表現します。

2. 認可コードフローをOIDCログインへつなぐ

RPはログイン開始時にstate、nonce、PKCEのcode_verifierを認可取引ごとに生成し、ブラウザの開始セッションへ結び付けます。認可要求にはscope=openid、response_type=code、client_id、redirect_uri、state、nonce、code_challengeを含めます。ここではprofileやemailの追加取得は必須にしません。

次のシーケンス図はブラウザ、RP、OP、UserInfoの通信方向を示します。UserInfoの呼出しは追加情報が必要な場合だけの処理です。

OIDC認可コードログインの順序架空のRPがOPでの認証結果を受け、Token EndpointでID Tokenを受け取り、検証後にローカルセッションを作る。Aのブラウザ請求書RPOPUserInfo1. ログイン開始2. 認可URLへ誘導3. openid要求4. codeとstate5. callback6. codeとverifier7. IDとAccess Token8. 必要なら照会9. subと追加情報10. アプリのセッション
OIDC認可コードログインの順序

架空のRPがOPでの認証結果を受け、Token EndpointでID Tokenを受け取り、検証後にローカルセッションを作る。

図の認可要求からcallbackまではブラウザを経由します。RPはstateを開始セッションと照合し、同じ取引のcode_verifierでcodeを交換します。Token Endpointから受けたID Tokenを検証し終えてから、issとsubに対応するローカル利用者へアプリ内セッションを発行します。UserInfoを呼ぶならsub一致を追加確認します。

2-1. 正常系の設定と時系列ログ

text
expected_issuer=https://id.partner.example
client_id=billing-web
redirect_uri=https://billing.example/oidc/callback
authorization_endpoint=https://id.partner.example/auth
token_endpoint=https://id.partner.example/token
jwks_uri=https://id.partner.example/jwks
allowed_id_token_alg=RS256

これはRP側に設定した信頼するOPの値です。実際の署名検証では、このissuerに対応する公開鍵だけを取得します。JWT内のissやkidを見て任意の別サイトから鍵を探す実装にはしません。

text
09:04 RP auth_start browser_session=B-41
  state_ref=S-41 nonce_ref=N-41 pkce_ref=P-41
09:04 Browser -> OP /auth
  response_type=code scope=openid
  client_id=billing-web state_ref=S-41
  nonce_ref=N-41 code_challenge_method=S256
09:05 OP authenticated sub=user-41
  auth_time=1790327100 consent=granted
09:05 OP -> Browser callback code_ref=C-41
  state_ref=S-41
09:05 RP callback state_match=true
  state_consumed=true
09:05 RP -> OP POST /token code_ref=C-41
  pkce_verifier_ref=P-41 client_auth=success
09:05 OP -> RP id_token_ref=ID-41
  access_token_ref=AT-41
09:05 RP validation=pass local_user_id=41
  app_session=created

このログでは09:05にOPがuser-41を認証し、RPはcallbackを受け、サーバ間の交換でID Tokenを得ています。validation=passは後述の署名・iss・aud・exp・nonce確認が済んだという架空の集約ログです。実際の製品で各項目のログが出るかは設定に依存するため、詳細ログと構成を照合します。

openid scopeはOIDC要求を識別する条件です。scope=openidがなくAccess Tokenだけ返る通常のOAuth認可を、ID Tokenによるログインと同じものとして扱いません。PKCEとstateの役割は前の記事と同じで、OIDCではさらにnonceをID Tokenへ結び付けます。

3. ID Tokenは何を表すJWTか

ID TokenはOPがEnd-Userを認証した事実に関するclaimを載せるJWTです。この例の署名付きJWT(JWS形式)は、Base64urlで表したヘッダ、ペイロード、署名の三部分をピリオドで結びます。ヘッダとペイロードは鍵なしでデコードして読めます。署名を正しい鍵とアルゴリズムで検証して初めて内容を信頼できます。

署名は改ざんの検知と発行元の検証に使いますが、内容を秘匿しません。暗号化する場合はJWE形式を使い、復号鍵が必要です。署名付きID Tokenに個人情報が入れば、Token全文をログへ残したり外部のデコードサイトへ貼ったりすると漏えいし得ます。

次はID-41を読みやすく分解した架空データです。実際の署名バイト列は省略しています。iatとauth_timeは09:05 UTC、expは09:15 UTCを表すNumericDateの秒数です。

text
JOSE header:
{"alg":"RS256","typ":"JWT","kid":"key-7"}

claims:
{
  "iss":"https://id.partner.example",
  "sub":"user-41",
  "aud":"billing-web",
  "exp":1790327700,
  "iat":1790327100,
  "auth_time":1790327100,
  "nonce":"nC5tP8vR2aM6xQ9bL3fH7kW4sD1yZ0uG"
}

signature: <説明のため省略>

nonce_ref=N-41は、実際には上の長いnonceに対応するログ用の参照値です。RPがログイン開始時に保管したnonceとID Token内のnonceを比べます。実際のnonceやトークン全文を通常ログに書かず、参照IDと検証結果を記録する例です。

3-1. 必須claimと、その値から言えること

  • iss:発行者識別子。RPが事前に信頼したhttps://id.partner.exampleと文字列として一致させます。ホスト名が似ているだけでは受け入れません。

  • sub:そのissの中で一意で再割当てされないEnd-User識別子です。ローカル利用者への対応はissとsubの組で保持します。emailや表示名を不変のIDとして使いません。

  • aud:ID Tokenを受け取るRPのclient_idを含む必要があります。この例はbilling-webです。別のClient向けの有効な署名付きTokenでも拒否します。

  • exp:この時刻以降、RPはそのID TokenをOPによる認証結果として受理しません。現在時刻との比較には小さい時計ずれ許容を設ける場合があります。

  • iat:ID Tokenの発行時刻です。現在より極端に未来の値や古い値を拒否する運用に使えますが、許容幅はRPの方針で決めます。

09:05にID-41を受け取ると、現在時刻はexpの09:15より前です。09:16に同じID Tokenで新しいログイン取引を成立させようとすれば拒否します。ただしexpはRPが作ったアプリ内セッションの終了時刻と同じではありません。ログイン後のセッション寿命、再認証、ログアウトはRPが別に設計します。

3-2. nonce、auth_time、audの複数値

nonceはRPが認証要求ごとに作る値です。要求に入れた場合、OPはID Tokenへ同じ値を載せ、RPは開始取引の値と照合します。nonceの使い回しや別ブラウザの値との混同を防ぐため、取引・ブラウザセッションへ結び付け、一回限りで扱います。認可コードフローでnonceの送信自体は常に必須という意味ではありません。

auth_timeはOPでEnd-Userが認証された時刻で、ID Tokenの発行時刻iatとは別です。以前のOPセッションを再利用すると、iatは今でもauth_timeは古い場合があります。max_ageを要求され、前回の認証からの経過時間がその値を超えていれば、OPは利用者の再認証を試みる必要があります。RPも返されたauth_timeで要求した新しさを確認し、iatだけで代用しません。

audは文字列または配列で表されます。配列にbilling-webが含まれていても、RPが信頼しない別のaudが同居すれば拒否します。複数audやazpがある場合は、プロファイルと登録条件に従って宛先Clientを確認します。単純に配列の先頭だけを見る実装では不十分です。

3-3. 任意のclaimを読んで過剰に断定しない

JWT一般のnbfは、指定時刻より前の受理を制限する任意claimです。OIDCのID Tokenで必ず付く値ではありません。nbfがあれば時計ずれを考慮して確認し、なければexpとiatの検証を省略しません。ヘッダのtyp=JWTも形式の目安であり、Tokenの用途や発行者を証明しません。

at_hashはAccess Tokenとの対応を確認するためのclaimです。この教材の認可コードフローでは必須ではありません。含まれていれば、署名アルゴリズムに対応したハッシュ計算でAccess Tokenと一致するか確認できます。ただしat_hashだけでAPI側のscopeや所有ファイルの認可は分かりません。

ID Tokenにないclaimから結論を作らないことも大切です。例えばamrがなければ使った認証手段はこのTokenからは分かりません。emailが載っていなければUserInfoなどで追加取得する設計を確認します。Tokenから読める属性と、RPが別途持つ利用者権限を分けて扱います。

4. 署名とclaimをどこで検証するか

ID Tokenを受け取るRPが検証を担当します。ヘッダにalg=RS256、kid=key-7と書いてあっても、それはまだ未検証の入力です。RPは信頼済みOPの設定から署名鍵の公開先jwks_uriを取得し、許可したアルゴリズムと鍵種別に合う公開鍵を選びます。JWT自身が示す任意の鍵URLへアクセスしません。

次の設定とログは、RPが受理した鍵の来歴と検証条件を追うための架空例です。JWKSはJSON Web Key Setの略で、OPが公開する署名検証用の公開鍵群です。kidは鍵を選ぶ手掛かりであり、kidだけで鍵の信頼性を証明しません。

text
trusted_issuer=https://id.partner.example
metadata_url=
  https://id.partner.example/.well-known/openid-configuration
metadata.issuer=https://id.partner.example
metadata.jwks_uri=https://id.partner.example/jwks
configured_alg=RS256
JWKS kid=key-7 kty=RSA use=sig
09:05 RP id_token_ref=ID-41
  header_alg=RS256 header_kid=key-7
  signing_input=base64url(header).base64url(payload)
  signature_valid=true key_source=trusted_JWKS
  iss_match=true aud_contains_client=true
  exp_valid=true nonce_match=true
  subject_key=(https://id.partner.example,user-41)
  result=accept

このRS256の例では、OPが秘密鍵で署名し、RPはJWKSのRSA公開鍵でヘッダとペイロードに対する署名を検証します。JWKのnとeは公開鍵の構成値です。公開鍵は署名を検証できますが、正規の署名を新しく作る鍵ではありません。kidは候補の公開鍵を選ぶために使います。

RPは署名を確認した上で、iss、aud、exp、nonceなどを期待値と比較し、全て通った後にsubをアプリの利用者へ対応付けます。単にペイロードをBase64urlデコードして画面に表示できたことや、kidがJWKSに見つかったことだけでは認証になりません。

4-1. 安全な検証順と鍵の選び方

  1. 取引を特定する。callbackのstateをブラウザの開始セッションへ結び付け、同じ取引のPKCE verifierでcodeを交換する。

  2. 信頼済みOPを特定する。RP設定のissuerとDiscoveryのissuerが一致することを確認し、登録済みエンドポイントとJWKSを使う。未検証JWTのissから鍵取得先を自由に決めない。

  3. JWT形式と署名方式を検査する。許可したalg、鍵種別、kidで鍵候補を選び、署名を検証する。alg=noneや想定外のMAC方式への切替えを受け入れない。

  4. claimを照合する。issの完全一致、audにbilling-webが含まれ余計な宛先がないこと、現在時刻がexpより前であること、要求したnonceの一致を確認する。

  5. 必要な条件を確認する。max_ageやauth_time、追加のacr方針、UserInfoを使うならsubの一致を確かめ、最後にローカル利用者へ対応付ける。

実装ではJWTを解析して鍵候補を選ぶ処理が署名確認より先になりますが、その段階のalg・kid・issは未信頼値です。RPが許可したissuerとアルゴリズムの範囲に限定して扱います。OIDC Coreには、認可コードフローでToken Endpointから直接受けたID Tokenについて、TLSサーバ検証を署名検証の代わりに使える条件もあります。この記事の構成は署名を検証する方針です。

署名が正しくても、別Client向けのToken、期限切れ、別取引のnonceなら拒否します。逆に、iss・aud・expの文字列が期待どおりでも署名が無効なら拒否します。署名は鍵を持つOPがその内容を発行したことを確かめるもので、Aが今この端末で操作したことやMFAを使ったことを単独で証明しません。

秘密鍵が侵害されていないという前提も残ります。鍵の来歴が正しく署名が検証できても、OPの認証ポリシー、利用者アカウントの侵害、RPのローカル権限設定は別問題です。試験で『署名成功』という一行が出たら、次にiss・aud・exp・nonce・subの照合結果と、必要なauth_timeを探します。

4-2. 鍵更新とkidの読み方

OPが署名鍵をkey-7からkey-8へ更新すると、新しいID Tokenのkidはkey-8になります。RPのJWKSキャッシュにkey-8がない場合は、信頼済みjwks_uriを再取得し、署名を検証します。再取得しても鍵がないならログインを保留し、alg制限や署名確認を無効にして通すことはしません。

text
09:40 RP received id_token_ref=ID-42
  header_kid=key-8 cached_kids=[key-7]
09:40 RP refresh_JWKS uri=trusted_jwks_uri
  fetched_kids=[key-7,key-8]
09:40 RP verify alg=RS256 kid=key-8
  signature_valid=true claims_valid=true
  result=accept

09:41 RP received id_token_ref=ID-43
  header_kid=unknown fetched_kids=[key-7,key-8]
  result=reject reason=key_not_found

09:40は正規の鍵更新でも一度キャッシュを更新する必要がある例です。09:41のunknown kidは鍵未配布、誤設定、不正なTokenのいずれもあり得ます。OPの公表した鍵更新、JWKSの取得状況、Token発行ログを照合します。鍵が見つからないだけで攻撃と断定しません。

5. 正常ログと異常ログの差を読む

ID Tokenの検証結果は、どの条件で止まったかに分けて記録します。以下のcase A〜Eは、同じ設定のRPへ異なるID Tokenが提示された架空の検証例です。署名付きの別Client向けTokenや別取引のTokenがRPへ届くには、応答差替え、誤配線、外部JWTを受け入れる不備などの入口が必要です。

text
case=A 09:05 ID-41
  sig=valid iss=match aud=billing-web
  exp=09:15 nonce=match -> accept
case=B 09:06 ID-B
  sig=invalid iss=match aud=billing-web
  exp=09:15 nonce=match -> reject
case=C 09:06 ID-C
  sig=valid iss=https://other.example
  aud=billing-web -> reject_issuer
case=D 09:06 ID-D
  sig=valid iss=match aud=other-client
  exp=09:15 -> reject_audience
case=E 09:16 ID-41
  sig=valid iss=match aud=billing-web
  exp=09:15 -> reject_expired

Bは見かけのclaimが正しくても署名が無効です。Cは検証環境のOP鍵で署名は有効でも、issに信頼外の値が書かれた模擬応答です。Dは正規OPの署名があっても宛先Clientが違います。Eは09:15を過ぎたTokenを新しいログイン判断に使おうとしています。各拒否は条件不一致を示しますが、攻撃者の身元は別の証拠が要ります。

5-1. nonce不一致と再利用

text
09:20 RP auth_start browser_session=B-41
  expected_nonce_ref=N-42 state_ref=S-42
09:21 RP callback state_match=true
  code_exchange=success id_token_ref=ID-X
09:21 RP validate ID-X
  sig=valid iss=match aud=match exp=valid
  token_nonce_ref=N-OLD nonce_match=false
  result=reject session_created=false

この例ではcallbackのstateとcode交換は通っています。しかしID Tokenのnonceは現在の取引N-42と違い、RPはセッションを作りません。過去の認証応答の再利用や取引の混同を疑いますが、RP側の保存ミスでも起こり得るため、開始取引、Token Endpointの応答、セッションIDを確認します。

stateはcallbackを開始したブラウザの取引へ結び付けます。PKCEは認可コード交換者が開始時のverifierを知ることを検査します。nonceはID Tokenをその認証取引へ結び付けます。同じ名前で代用できる値ではありません。認可コードフローでnonceを送らない構成も規格上あり、この事例では送ったため一致確認が必須です。

5-2. 複数audとazpの例外

text
ID-Y: iss=https://id.partner.example
  aud=[billing-web,unknown-app]
  azp=billing-web sig=valid -> reject
ID-Z: iss=https://id.partner.example
  aud=[billing-web,trusted-helper]
  azp=billing-web sig=valid
  extra_audience_trusted=true -> continue_checks

ID-Yはbilling-webを含みますが、信頼しないunknown-appも含むため拒否します。ID-Zは追加のaudをRPが信頼する設定がある例です。azpはTokenが主としてどのClient向けかを補助しますが、azpがbilling-webなら無条件に他のaudを許してよいわけではありません。いずれも署名、exp、nonceなど残りの検証は必要です。

6. subでローカル利用者へ結び付ける

RPは検証済みID Tokenのissとsubの組をローカル利用者IDへ対応付けます。この例では(https://id.partner.example, user-41)を整数ID 41へ対応付けます。別OPのuser-41は同一人物とは限りません。email、表示名、メールドメインを自動的に利用者IDや権限の根拠へしません。

text
id_token.iss=https://id.partner.example
id_token.sub=user-41
local_mapping=(issuer,subject) -> user_id=41
local_role=accounting

UserInfo response:
  sub=user-41
  email=a@example.com
  email_verified=true
userinfo_sub_match=true
profile_update=allowed

UserInfoのsubがID Tokenのsubと一致すれば、追加のプロフィール情報をその利用者へ結び付けられます。UserInfoから異なるsubが返れば、その情報は使いません。email_verifiedはOPがメールアドレスを検証したというclaimですが、アプリ内の管理者権限や支払承認を与える根拠にはしません。

利用者Aが別のOPへ移行した場合、同じemailでもissとsubが変わり得ます。管理者が本人確認と移行手順を決めて対応付けを更新します。メール一致だけで旧アカウントへ自動連結すると、別人のアカウント取得につながります。

7. 認証の新しさ、セッション、鍵事故を分ける

ID Tokenの署名と基本claimが正しくても、業務操作に必要な認証の新しさや強さを満たすとは限りません。また、ID Tokenの期限とRPが発行するWebセッションの期限は独立です。OPの鍵更新や漏えいが起きた場合、Token受理と既存セッションの扱いも分けて判断します。

7-1. max_age、auth_time、acr・amr

例えば請求書の振込先変更では、RPが認証から5分以内という方針を持つとします。RPがmax_age=300を要求し、前回の認証から5分を超えていれば、OPは利用者の再認証を試み、ID Tokenへauth_timeを含める必要があります。RPも現在時刻とauth_timeを比べ、古ければ受理しません。iatはToken発行時刻であり、この代わりになりません。

text
09:20 RP auth_request max_age=300
09:21 OP reauthentication_attempt=absent
09:21 OP id_token iat=1790328060
  auth_time=1790326200
  auth_time_utc=08:50
09:21 RP now=09:21 age=31min
  max_age=5min result=reject_stale_auth
  next_action=request_reauthentication

これはOPが再認証を試みず、古いauth_timeのままID Tokenを返した異常例です。Aの最後の認証は08:50なので、09:21には31分が経過しています。RPはこの取引を拒否し、OP側でmax_ageが処理されたか調査します。再認証後に新しいauth_timeを確認してから振込先変更を許可します。

acrは認証コンテキストの識別値、amrは使った認証手段を表す場合があるclaimです。両者の値の意味や必要な強さはOPとRPの取り決めに依存します。acrやamrがないID TokenからMFA実施を推測しません。MFA必須の操作なら、RPが要求した値と検証条件を明示します。

7-2. ID Token期限とアプリ内セッション

text
09:05 RP ID-41 validation=pass
  id_token_exp=09:15 app_session=SESS-41
09:16 RP app_request session=SESS-41
  session_active=true -> process_local_request
09:16 RP new_oidc_login id_token_ref=ID-41
  token_expired=true -> reject

09:16にID-41は新たなログイン判定には使えません。一方、RPのSESS-41は別に有効期限を管理しており、この例では有効です。OPからログアウトしただけでRPのセッションが必ず消えるわけでもありません。RP側のログアウト、セッション失効、再認証の条件を別に設計します。

7-3. 署名鍵の侵害を疑った場合

OPの署名鍵が漏れた疑いがあれば、その鍵で署名されたTokenは、署名検証だけでは正規発行と区別できません。OPの事故情報、鍵ID、発行期間、RPのログイン履歴、各セッションの開始時刻を突き合わせます。単にJWKSを再取得して新しい鍵が見えたことだけでは、既存セッションの影響を評価し終えたことになりません。

次の図は、OPの鍵事故が通知されたときのRP側の作業です。鍵の通常更新とは異なり、事故では受理済みTokenとアプリ内セッションへの影響も調べます。

署名鍵事故後のRPの確認架空のOPからkey-7の漏えい疑いが通知された場合。鍵の受理停止、既存ログイン調査、再認証、再開条件を分ける。1対象を絞る2受理を止める3セッション調査4再認証と再開
署名鍵事故後のRPの確認
  1. 1. 対象を絞る:対応 key-7の発行期間を確認/確認する証跡 OP通知とRPログ
  2. 2. 受理を止める:対応 危険な鍵を除外/確認する証跡 設定と拒否ログ
  3. 3. セッション調査:対応 該当ログインを照合/確認する証跡 subと開始時刻
  4. 4. 再認証と再開:対応 新鍵で検証/確認する証跡 正常・異常試験

架空のOPからkey-7の漏えい疑いが通知された場合。鍵の受理停止、既存ログイン調査、再認証、再開条件を分ける。

RPはOPと失効・鍵交換の範囲を確認し、危険な鍵による新しいTokenを受け付けない設定へ切り替えます。必要な既存セッションを失効させて再認証を求め、正規の新鍵でのログインと旧鍵・不正claimの拒否を確認します。どの利用者が影響したかは、署名鍵IDとRPの取引・セッションログがなければ確定できません。

8. 科目B(午後)の記述演習

解答では、どの主体が何を検証したか、ログから確定できること、追加で必要な証拠を分けてください。署名が有効という一項目だけでログイン成功と答えない練習です。

演習1:OAuthのAccess Tokenでログインしてよいか

条件:billing.exampleはToken EndpointからAccess Tokenを受け取りましたが、scopeはfiles:readでID Tokenはありません。開発者はAccess Tokenの文字列を復号して利用者IDを取りたいと考えています。問い:判断と必要な仕組みを答える。

解答:このAccess TokenはAPIへの委譲権限で、billing.example向けの認証結果とは確認できません。利用者ログインにはOIDCのopenid要求と、RP向けID Tokenの検証を使います。API用Tokenの形式も必ずJWTとは限りません。

誤答の理由:『Token Endpointが発行したので本人確認済み』はTokenの宛先と目的を無視しています。『JWTならsubを読むだけでよい』は署名とaudの検証を欠きます。

演習2:iss・aud・expを同時に読む

条件:RPの信頼するissはhttps://id.partner.example、client_idはbilling-webです。09:06に署名有効、iss一致、aud=other-client、exp=09:15のID Tokenを受けました。問い:受理できるか、理由と追加確認を答える。

解答:受理しません。署名と期限が正しくても、audにRPのbilling-webがなく、別Client向けです。Tokenの来歴、応答の取引ID、認可コード交換やRP側のToken混同を調べます。

誤答の理由:『同じOPの署名だから受理』は宛先Clientの検証を省いています。『期限内なら安全』はiss・aud・nonce・署名の条件を無視しています。

演習3:署名未検証のJWT

条件:JWTをBase64urlデコードするとiss、aud、expが期待値でした。しかしRPはJWKS取得に失敗し、signature_validを記録していません。問い:ログイン処理と調査を答える。

解答:認証済みセッションを作りません。信頼済みissuerのjwks_uri、通信・キャッシュ、kid、許可したalgを確認し、署名検証が通ってからclaimを使います。JWTヘッダが示す任意URLへ鍵取得を広げません。

誤答の理由:『claimが読めるので発行者を信じる』は改ざん可能な入力を信用しています。『鍵がないので署名確認を無効化』は偽造Tokenの受理につながります。

演習4:nonceの不一致

条件:state一致、code交換成功、ID Tokenの署名・iss・aud・expは正常です。保存されたnonce_ref=N-42に対し、Token内はN-OLDでした。問い:RPの処理と疑う原因を答える。

解答:ID Tokenを拒否し、アプリ内セッションを作りません。別取引の応答の再利用や差替え、RPのnonce保存・取引対応の誤りを調べます。nonceを要求した取引なので、一致確認が必要です。

誤答の理由:『stateが一致すればnonceは無視できる』はID Tokenと認証要求の対応を確かめていません。『署名が有効なら同じ利用者』も別取引の可能性を残します。

演習5:auth_timeとiatの違い

条件:振込先変更では5分以内の認証が必要です。09:21に発行されたTokenのauth_timeは08:50で、RPはmax_age=300を要求していました。問い:操作を許可できるか。

解答:許可できません。auth_timeから31分が経過しています。iatが09:21でも、OPでの利用者認証が新しくなった証拠にはなりません。OPがmax_ageに応じて再認証を試みたか調べ、再認証後のauth_timeと必要ならacr・amrの条件を確認します。

誤答の理由:『新しいTokenなので再認証済み』はiatとauth_timeを混同しています。『expが未来なら業務要件を満たす』は認証の新しさを見ていません。

演習6:UserInfoのsub不一致

条件:検証済みID Tokenのsubはuser-41、UserInfo応答のsubはuser-42です。UserInfoにはemail=a@example.comとあります。問い:UserInfoの扱いと利用者識別方法を答える。

解答:UserInfoのclaimをuser-41に適用しません。応答の取り違えやToken差替えを調べ、利用者の識別は検証済みID Tokenのissとsubの組で行います。email一致だけで別subを同一人物にしません。

誤答の理由:『emailが同じなら受け入れる』はsubの不一致を無視しています。『UserInfoを受けたのでID Tokenの検証不要』は認証の根拠を失います。

演習7:新しいkidが現れた

条件:RPのJWKSキャッシュはkey-7だけです。OPから届いたID Tokenのkidはkey-8で、RPは署名をまだ検証できません。問い:安全な確認と再開条件を答える。

解答:設定済みissuerのjwks_uriを再取得し、正規に公開されたkey-8と許可したalgで署名を検証します。鍵取得に失敗する間はTokenを受け入れず、OPの更新情報も確認します。新鍵の正常Tokenを受理し、未知鍵・無効署名を拒否できることが再開条件です。

誤答の理由:『kidが新しいので攻撃確定』は通常の鍵更新を考慮していません。『kidが合わない間は署名確認を飛ばす』は偽造を許します。

演習8:ID Tokenが期限切れでもWeb画面を開けた

条件:ID-41は09:15に期限切れですが、09:16にRPのWeb画面はSESS-41で開けました。問い:矛盾かどうかと、何の有効性を確認すべきか。

解答:矛盾とは限りません。ID Tokenのexpは新しい認証結果としての受理期限で、RPのWebセッションは別に管理します。SESS-41の発行・期限・失効条件と、重要操作での再認証方針を確認します。

誤答の理由:『ID Tokenが切れたらRPセッションも必ず終了』は二つの寿命を同一視しています。『画面が開けるから期限切れTokenも有効』も成り立ちません。

9. 一次資料

OpenID Connect Core 1.0:ID Token、nonce、検証条件

OpenID Connect Discovery 1.0:issuerとjwks_uri

RFC 7519:JWTのclaimとNumericDate

RFC 7515:JWSの署名構造

RFC 7517:JWKとJWKSの鍵表現

RFC 8725:JWTのアルゴリズムと鍵の検証

RFC 9700:OAuth 2.0の現行セキュリティ推奨

この記事についてAIに深掘り質問する

ChatGPT、Claude、Perplexityにこの記事を参照させ、要点の確認や疑問点を自由に質問できます。

次におすすめの学習

編集・検証について

編集・検証:IT資格ラボ編集部

IPAが公開する試験要綱・シラバス・過去問題と、各技術の公式資料を優先して内容を確認しています。制度変更や誤りを確認した場合は、記事を見直して更新します。

編集方針・情報源・訂正方針を見る
この記事を共有する