LESSON 30分

ストーリー

田中VPoE
アイデンティティ管理の全体像を掴んだ。次は「認証」を深掘りする。「あなたは誰か」を証明する仕組みだ
あなた
OAuth 2.0とJWTは使ったことがあります
田中VPoE
実装したことがあるのと、セキュリティアーキテクチャとして設計できるのは別の話だ。OAuth 2.0のどのフローをどの場面で使うか、JWTの署名方式に何を選ぶか、MFAの方式をどう選定するか。これらを体系的に理解していないと、見た目は動くが穴のある認証基盤ができる
あなた
動くけどセキュアではない、という状態ですか
田中VPoE
そうだ。例えば、SPAからImplicit GrantでアクセストークンをURLフラグメントで受け取る実装。動くが、トークンがブラウザ履歴やRefererヘッダーで漏洩する。Authorization Code Flow + PKCEを使うべきだ

OAuth 2.0 / OIDC のフロー選定

フロー比較

フロー用途セキュリティ推奨度
Authorization Code + PKCESPA、モバイルアプリ高(認可コード + PKCE検証)推奨
Authorization CodeサーバーサイドWebアプリ高(Client Secret保護)推奨
Client Credentialsサーバー間通信(M2M)中(Client Secret必須)推奨(M2M用)
Implicit GrantSPA(旧方式)低(トークンがURLに露出)非推奨
Resource Owner Password信頼できるアプリ(旧方式)低(パスワードをアプリに渡す)非推奨
Device AuthorizationTVやIoTデバイス限定的に推奨

Authorization Code + PKCE フロー

Authorization Code + PKCE フロー(SPA向け推奨):

[ユーザー] ──→ [SPA]

                │ 1. code_verifier(ランダム文字列)を生成
                │    code_challenge = SHA256(code_verifier)

                │ 2. 認可リクエスト(code_challenge付き)

            [認可サーバー(IdP)]

                │ 3. ユーザー認証 + 同意

                │ 4. 認可コード発行(フロントチャネル)

            [SPA]

                │ 5. トークンリクエスト
                │    (認可コード + code_verifier)

            [認可サーバー]

                │ 6. code_verifier を検証
                │    SHA256(code_verifier) == code_challenge ?

                │ 7. アクセストークン + リフレッシュトークン発行

            [SPA] ──→ [API](アクセストークンで認証)

JWT(JSON Web Token)の設計

JWT の構造と署名方式

署名方式アルゴリズム鍵の種類用途
RS256RSA + SHA-256非対称鍵(公開鍵 + 秘密鍵)マイクロサービス(検証側は公開鍵のみ)
ES256ECDSA + SHA-256非対称鍵(楕円曲線)推奨(RSA256より高速、鍵が小さい)
HS256HMAC + SHA-256共有鍵単一サービス(検証側にも秘密鍵必要)
EdDSAEd25519非対称鍵最新推奨(高速、高セキュリティ)

JWTのセキュリティベストプラクティス

プラクティス理由実装
短いTTLトークン漏洩時の影響を限定accessToken: 15分、refreshToken: 7日
aud/issクレームの検証トークンの不正利用を防止必ずサーバーサイドで検証
algヘッダーの固定alg
サーバーで許可するalgを固定
JWKSエンドポイント公開鍵のローテーション対応/.well-known/jwks.json
リフレッシュトークンローテーションリプレイ攻撃の防止使用済みリフレッシュトークンを無効化
// JWT検証の安全な実装例(TypeScript)
import * as jose from "jose";

const JWKS = jose.createRemoteJWKSet(
  new URL("https://auth.example.com/.well-known/jwks.json")
);

async function verifyToken(token: string): Promise<jose.JWTPayload> {
  const { payload } = await jose.jwtVerify(token, JWKS, {
    issuer: "https://auth.example.com",
    audience: "https://api.payconnect.com",
    algorithms: ["ES256"], // 許可するアルゴリズムを固定
    maxTokenAge: "15m",    // 最大有効期間
  });

  return payload;
}

MFA(多要素認証)

MFA方式の比較

方式セキュリティユーザー体験フィッシング耐性推奨度
パスキー(FIDO2/WebAuthn)最高優(生体認証)あり最推奨
ハードウェアキー(YubiKey)最高良(物理操作)あり推奨(高セキュリティ)
認証アプリ(TOTP)なし推奨
プッシュ通知中〜高限定的条件付き推奨
SMS OTP低〜中なし非推奨(SIMスワップ攻撃のリスク)
メール OTPなし非推奨

パスキー(FIDO2/WebAuthn)の仕組み

パスキー認証フロー:

登録(Registration):
  [ユーザー] ──→ [ブラウザ] ──→ [認証サーバー]
  1. サーバーがチャレンジを送信
  2. ユーザーが生体認証(指紋/顔)でデバイス上の秘密鍵を使用
  3. チャレンジに署名して返送
  4. サーバーが公開鍵を保存

認証(Authentication):
  [ユーザー] ──→ [ブラウザ] ──→ [認証サーバー]
  1. サーバーが新しいチャレンジを送信
  2. ユーザーが生体認証で秘密鍵を使用
  3. チャレンジに署名して返送
  4. サーバーが保存済み公開鍵で署名を検証

フィッシング耐性:
  - 秘密鍵はデバイスから出ない
  - オリジン(ドメイン)がバインドされている
  - 偽サイトではパスキーが動作しない

リスクベース認証

コンテキストに基づく認証強度の動的制御

シグナル低リスク高リスク
場所いつものオフィス海外からのアクセス
デバイス登録済みデバイス未知のデバイス
時間帯業務時間内深夜
行動通常の操作パターン大量のデータダウンロード
ネットワーク社内ネットワークTor/VPN経由
リスクレベル認証要件
低リスクパスワード + 既知デバイス → アクセス許可
中リスクパスワード + MFA → アクセス許可
高リスクパスワード + MFA + セキュリティチームへの通知
非常に高リスクアクセスブロック + セキュリティ調査

まとめ

ポイント内容
OAuth 2.0 フローSPA: Auth Code + PKCE、M2M: Client Credentials、Implicit: 非推奨
JWT設計ES256/EdDSA推奨、短いTTL、aud/iss検証、alg固定
MFAパスキーが最推奨、SMS OTPは非推奨
リスクベース認証コンテキストに応じて認証強度を動的に制御

チェックリスト

  • OAuth 2.0の各フローの適用場面を説明できる
  • JWTのセキュリティベストプラクティスを実装できる
  • MFA方式のセキュリティレベルを比較できる
  • リスクベース認証の設計方針を理解した

次のステップへ

次は「認可モデルの設計」を学びます。RBAC、ABAC、ReBAC等の認可モデルを比較し、適切な認可アーキテクチャを設計しましょう。


推定読了時間: 30分