目次

  1. 基本概念
  2. 認証方式の選び方
  3. OAuth 2.0 / OpenID Connect
  4. トークン設計(JWT など)
  5. API キー
  6. 認可(アクセス制御)
  7. 通信とクレデンシャルの保護
  8. サービス間認証
  9. 防御・運用
  10. よくあるアンチパターン
  11. チェックリスト
  12. 参考資料

1. 基本概念

用語意味問い
認証(Authentication / AuthN)呼び出し元が誰かを確認する「あなたは誰?」
認可(Authorization / AuthZ)その主体が操作してよいかを判断する「それをしてよい?」
  • 認証と認可は別のレイヤーとして設計する。「ログインしている=何でもできる」にしない。
  • 認可はリクエストごと・リソースごとに評価する。

2. 認証方式の選び方

ユースケース推奨方式
ブラウザ SPA / モバイルアプリからの API 呼び出しOAuth 2.0 認可コードフロー + PKCE
ユーザーのログイン(ID 連携)OpenID Connect(OIDC)
サーバー間(マシン間)通信OAuth 2.0 Client Credentials、mTLS、ワークロード ID
外部開発者向けの公開 APIOAuth 2.0(ユーザーデータ扱い時)または API キー(公開データ・利用量管理用)
同一ドメインの従来型 Web アプリサーバーサイドセッション + Cookie(HttpOnly / Secure / SameSite)
社内のサービスメッシュmTLS + SPIFFE などのワークロード ID

原則: 独自の認証プロトコルを発明しない。実績ある標準と、メンテされているライブラリ / IdP を使う。


3. OAuth 2.0 / OpenID Connect

推奨フロー

  • 認可コードフロー + PKCE を標準にする。 パブリッククライアント(SPA・モバイル)だけでなく、コンフィデンシャルクライアントでも PKCE を使う。
  • PKCE の code_challenge_method は S256 を使う(plain は使わない)。
  • ブラウザアプリでは BFF(Backend for Frontend)パターン を検討する。トークンをサーバー側で保持し、ブラウザには HttpOnly Cookie のセッションだけを渡すことで、XSS によるトークン窃取リスクを下げられる。

使ってはいけないフロー

フロー理由
Implicit Grantアクセストークンが URL フラグメントに露出する。OAuth 2.0 Security BCP(RFC 9700)で非推奨
Resource Owner Password Credentialsクライアントがユーザーのパスワードを直接扱う。同上で非推奨

実装上の注意

  • redirect_uri は完全一致で検証する(ワイルドカードや前方一致は使わない)。
  • state パラメータ(または PKCE)で CSRF を防ぐ。OIDC では nonce も検証する。
  • スコープは最小限に絞り、機能単位で細かく定義する(例: orders:read, orders:write)。
  • 認可サーバーのメタデータ(/.well-known/openid-configuration)から設定を取得し、ハードコードを避ける。
  • OAuth 2.1(策定中のドラフト)は上記のベストプラクティスを取り込んだ仕様なので、新規実装はこれに沿っておくと将来の移行が楽になる。

4. トークン設計(JWT など)

アクセストークン

  • 有効期限を短くする(目安: 5〜15 分程度)。
  • 用途(audience)を限定し、API 側で aud を必ず検証する。
  • トークンには必要最小限のクレームのみを含める。個人情報や機密情報を入れない(JWT は署名されていても暗号化はされていない)。

JWT の検証で必ず確認すること

項目内容
署名期待するアルゴリズムをサーバー側で固定(ヘッダーの alg を信用しない)。alg: none は拒否
iss信頼する発行者か
aud自分の API 宛てか
exp / nbf / iat有効期間内か(数十秒程度のクロックスキューを許容)
kidJWKS から鍵を取得。JWKS はキャッシュしつつ、ローテーションに追従する
  • 署名アルゴリズムは非対称鍵(RS256, ES256, EdDSA など)を推奨。複数サービスで検証する場合、共有秘密(HS256)は秘密の漏洩範囲が広がる。

リフレッシュトークン

  • ローテーション(使用のたびに新しいリフレッシュトークンを発行し、古いものを無効化)を有効にする。
  • 再利用(リプレイ)を検知したら、そのトークンファミリー全体を失効させる。
  • 絶対有効期限とアイドルタイムアウトを設定する。
  • 可能であれば 送信者制約付きトークン(DPoP や mTLS バインディング)で、盗まれたトークンを別端末で使えないようにする。

失効(Revocation)

  • JWT は自己完結型のため即時失効が難しい。対策として:
    • アクセストークンの有効期限を短くする
    • 高リスク操作では Token Introspection(RFC 7662)で都度確認する
    • 必要に応じて失効リスト(jti ベース)を持つ
  • ログアウト・パスワード変更・権限変更時にリフレッシュトークンを失効させる。

クライアント側の保管

保管場所評価
HttpOnly + Secure + SameSite Cookie(BFF 経由)推奨
メモリ(JS 変数)許容。リロードで消える前提で設計
localStorage / sessionStorage非推奨。XSS で容易に読み取られる
モバイルOS のセキュアストレージ(iOS Keychain / Android Keystore)

5. API キー

API キーは「アプリケーションの識別」には有効だが、ユーザーの認証手段としては不十分。

  • 十分なエントロピーを持つランダム値で生成する(例: 32 バイト以上)。
  • サーバー側にはハッシュ化して保存する(平文で保存しない)。
  • 識別しやすいプレフィックスを付ける(例: sk_live_...)。漏洩検知(シークレットスキャン)に引っかかりやすくなる。
  • キーごとにスコープ・IP 制限・レート制限を設定できるようにする。
  • ローテーションを前提に設計する(新旧キーの並行稼働期間を設ける)。
  • URL のクエリパラメータではなく Authorization ヘッダーで送る(クエリはログやリファラーに残る)。
  • クライアントサイド(ブラウザ・モバイルアプリのバイナリ)に秘密のキーを埋め込まない。

6. 認可(アクセス制御)

基本原則

  • デフォルト拒否(Deny by default): 明示的に許可されていないものは拒否する。
  • 最小権限の原則: 必要な権限だけを付与する。
  • サーバー側で強制: クライアント側の UI 制御はセキュリティ対策ではない。
  • 一元化: 認可ロジックをハンドラーごとに散在させず、ミドルウェアやポリシーエンジンに集約する。

オブジェクトレベル認可(BOLA / IDOR 対策)

OWASP API Security Top 10 で最上位のリスク。

GET /api/orders/12345
  • 「認証済みであること」だけでなく、「このユーザーがこの注文 12345 にアクセスしてよいか」を毎回確認する。
  • データ取得時に所有者条件を含める(例: WHERE id = ? AND tenant_id = ?)。
  • 推測困難な ID(UUID など)を使うのは補助策であり、認可チェックの代わりにはならない。

機能レベル・プロパティレベル認可

  • 管理者用エンドポイントを「URL が知られていないから安全」としない(BFLA 対策)。
  • レスポンスで返すフィールド、更新を許可するフィールドを明示的に制御する(Mass Assignment / 過剰なデータ露出の防止)。
    • 例: 一般ユーザーが PATCH /users/me で role や is_admin を変更できないようにする。

認可モデルの選択

モデル特徴向いているケース
RBAC(ロールベース)ロールに権限を紐付け権限体系が比較的単純
ABAC(属性ベース)ユーザー・リソース・環境の属性で判断部署・時間帯・地域など条件が多い
ReBAC(関係ベース)リソース間の関係で判断(Google Zanzibar 型)ドキュメント共有、組織階層など
  • 複雑なポリシーは OPA(Open Policy Agent)、Cedar、OpenFGA などのポリシーエンジンの利用を検討する。

マルチテナント

  • すべてのクエリにテナント境界の条件を強制する(ORM のグローバルスコープ、DB の行レベルセキュリティなど)。
  • トークン内のテナント ID と、リクエスト対象リソースのテナント ID を照合する。

7. 通信とクレデンシャルの保護

  • TLS を必須にする(TLS 1.2 以上、可能なら 1.3)。HTTP は拒否、HSTS を設定する。
  • クレデンシャルは Authorization ヘッダーで送る。URL に含めない。
  • ログ・エラーメッセージ・トレースにトークンやパスワードを出力しない(マスキングする)。
  • シークレットはソースコードや環境設定ファイルにハードコードせず、シークレットマネージャー(AWS Secrets Manager、GCP Secret Manager、HashiCorp Vault など)で管理する。
  • CI にシークレットスキャン(gitleaks、GitHub Secret Scanning など)を組み込む。
  • 署名鍵は定期的にローテーションし、JWKS で新旧の鍵を並行公開する。

8. サービス間認証

  • 「社内ネットワークだから信頼する」をやめ、ゼロトラストを前提にする。
  • 選択肢:
    • mTLS: 双方向の証明書認証。サービスメッシュ(Istio、Linkerd など)で自動化しやすい。
    • OAuth 2.0 Client Credentials: サービスごとにクライアント ID と最小スコープを付与。
    • ワークロード ID: クラウドのマネージド ID(AWS IAM Role、GCP Workload Identity、Azure Managed Identity)や SPIFFE/SPIRE を使い、長期のシークレットを持たない。
  • ユーザーの代理で下流サービスを呼ぶ場合は、ユーザーのトークンをそのまま転送せず、Token Exchange(RFC 8693) で下流用の権限を絞ったトークンを取得する。

9. 防御・運用

ブルートフォース・不正利用対策

  • ログイン・トークン発行エンドポイントにレート制限をかける(IP 単位とアカウント単位の両方)。
  • 認証失敗時のメッセージは汎用的にする(「ユーザーが存在しません」と「パスワードが違います」を区別しない)。
  • 重要操作や管理者アカウントには MFA を必須にする。フィッシング耐性のある方式(パスキー / WebAuthn)を優先する。
  • パスワードを保存する場合は Argon2id、bcrypt、scrypt などの低速ハッシュを使う。

ステータスコード

状況コード
認証情報がない・無効401 Unauthorized(WWW-Authenticate ヘッダーを付与)
認証済みだが権限がない403 Forbidden
リソースの存在自体を隠したい404 Not Found

監査とモニタリング

  • 認証の成功 / 失敗、トークン発行、権限変更、認可拒否を監査ログに記録する(誰が・いつ・何に・結果)。
  • 異常検知: 短時間の大量失敗、通常と異なる地域・端末からのアクセス、リフレッシュトークンの再利用など。
  • ログ自体へのアクセスも制御し、改ざんを防ぐ。

テスト

  • 認可のテストを自動化する。特に「ユーザー A がユーザー B のリソースにアクセスできないこと」を明示的にテストする。
  • 期限切れ・署名不正・aud 不一致・スコープ不足のトークンが拒否されることをテストする。
  • 定期的にペネトレーションテストや DAST を実施する。

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

アンチパターン問題点対策
独自の暗号・トークン形式を実装脆弱性を作り込みやすい標準仕様と実績あるライブラリを使う
JWT の alg をヘッダーから信用none や鍵混同攻撃を受ける許可アルゴリズムをサーバー側で固定
有効期限なし / 非常に長いアクセストークン漏洩時の被害が長期化短命トークン + リフレッシュ
トークンを localStorage に保存XSS で窃取されるBFF + HttpOnly Cookie
ID が推測困難だから認可チェック不要BOLA 脆弱性毎回所有者・権限を確認
クライアントから送られた role / user_id を信用権限昇格検証済みトークンからのみ主体を取得
API キーをフロントエンドに埋め込む誰でも取得できるサーバー側で保持・プロキシする
トークンや API キーをログに出力ログ経由で漏洩マスキング
内部 API は認証なし侵入後の横展開を許すmTLS / ワークロード ID

11. チェックリスト

認証

  • 標準プロトコル(OAuth 2.0 / OIDC)と信頼できるライブラリ・IdP を使っている
  • 認可コードフロー + PKCE(S256)を使い、Implicit / ROPC を使っていない
  • redirect_uri を完全一致で検証している
  • アクセストークンが短命で、iss / aud / exp / 署名を検証している
  • リフレッシュトークンのローテーションと再利用検知を行っている
  • ブラウザでトークンを localStorage に保存していない
  • 重要操作に MFA を要求している

認可

  • デフォルト拒否になっている
  • すべてのエンドポイントでオブジェクトレベルの認可チェックをしている
  • 管理者機能に機能レベルの認可チェックがある
  • 更新可能なフィールドを明示的に制限している
  • マルチテナントの境界がデータアクセス層で強制されている
  • 認可ロジックが一元化されている

運用

  • TLS 必須、HSTS 設定済み
  • シークレットをシークレットマネージャーで管理し、コードに含めていない
  • ログにクレデンシャルが出力されない
  • 認証エンドポイントにレート制限がある
  • 認証・認可イベントの監査ログがある
  • 認可の自動テスト(他ユーザーのリソースへのアクセス拒否など)がある
  • 鍵・API キーのローテーション手順が確立している

12. 参考資料

0件のページ