Skip to content

필사 모드: SSO クッキー/JWT認証システム完全ガイド — フレームワーク別実践シリーズインデックス

日本語
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

シリーズ紹介 — なぜこのシリーズを書くのか

Web認証はシンプルではありません。「ログイン機能を1つ作ればいい」と考えがちですが、実践では以下のような疑問が次々と湧いてきます。

- トークンを**クッキー**に入れるか、**localStorage**に入れるか?

- **JWT**と**セッション**のどちらを選ぶべきか?

- **HttpOnly Cookie**と**CSRFトークン**をどう組み合わせるか?

- **SSO(Single Sign-On)**環境で複数サービス間の認証状態をどう共有するか?

- **Access Token更新**はフロントエンドで行うか、バックエンドで行うか?

- **CORS**と**credentials**設定はなぜいつも苦労するのか?

これらの質問の正解は**フレームワークによって異なります**。Spring Bootの`SecurityFilterChain`とDjangoの`SessionMiddleware`は基本戦略から違いますし、React SPAとNext.js SSRはクッキーを扱う方式自体が異なります。公式ドキュメントだけでは全体像を描くのが困難です。

このシリーズは**認証システムの全体マップ**をまず広げた後、フレームワーク別に実践コードを実装する構成です。

**シリーズが扱う範囲:**

- SSO / OAuth 2.0 / OIDCプロトコルの動作原理

- クッキーベース認証とJWTベース認証の違い、長所短所、ハイブリッド戦略

- ブラウザストレージ(Cookie、localStorage、sessionStorage、Memory)別のセキュリティ特性

- CORS + Credential送信の正確な設定方法

- Spring Boot、Django、React、Next.js各フレームワークでの実践実装

- 複数フレームワークを組み合わせたハイブリッドアーキテクチャ設計

認証フロー全体マップ

認証システムの全体フローを一目で把握しましょう。以下はSSO/OIDCベースのログインからトークン更新、ログアウトまでの全プロセスです。

ログインフロー

┌──────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────┐

│ Browser │ │ Frontend │ │ Backend │ │ IdP │

│(ユーザー)│ │ (React/Next) │ │ (Spring/ │ │ (Keycloak│

│ │ │ │ │ Django) │ │ Okta) │

└────┬─────┘ └──────┬───────┘ └──────┬───────┘ └────┬─────┘

│ 1. ログインクリック │ │ │

│─────────────────▶│ │ │

│ │ 2. /auth/login │ │

│ │───────────────────▶│ │

│ │ │ 3. Redirect URL │

│ │ │─────────────────▶│

│ 4. IdPログインページ │ │

│◀──────────────────────────────────────────────────────────│

│ 5. ユーザー認証(ID/PW, MFA) │ │

│──────────────────────────────────────────────────────────▶│

│ │ │ 6. Auth Code │

│ │ │◀─────────────────│

│ │ 7. Code → Token │ │

│ │◀───────────────────│ │

│ │ │ (id_token + │

│ │ │ access_token + │

│ │ │ refresh_token) │

│ 8. Set-Cookie: │ │ │

│ access_token │ │ │

│ (HttpOnly) │ │ │

│◀─────────────────│ │ │

│ 9. 認証完了、 │ │ │

│ ダッシュボードへ │ │ │

│◀─────────────────│ │ │

認証済みリクエストフロー

┌──────────┐ ┌──────────────┐ ┌──────────────┐

│ Browser │ │ Frontend │ │ Backend │

└────┬─────┘ └──────┬───────┘ └──────┬───────┘

│ APIリクエスト │ │

│─────────────────▶│ │

│ │ Cookie自動送信 │

│ │ (access_token) │

│ │───────────────────▶│

│ │ │ JWT検証

│ │ │ (署名、期限、クレーム)

│ │ 200 + データ │

│ │◀───────────────────│

│ レンダリング │ │

│◀─────────────────│ │

トークン更新フロー

┌──────────┐ ┌──────────────┐ ┌──────────────┐

│ Browser │ │ Frontend │ │ Backend │

└────┬─────┘ └──────┬───────┘ └──────┬───────┘

│ APIリクエスト │ │

│─────────────────▶│ │

│ │ Cookie送信 │

│ │───────────────────▶│

│ │ 401 Unauthorized │

│ │◀───────────────────│

│ │ │

│ │ POST /auth/refresh│

│ │ (refresh_token │

│ │ Cookie送信) │

│ │───────────────────▶│

│ │ 新access_token │

│ │ Set-Cookie │

│ │◀───────────────────│

│ │ │

│ │ 元のリクエスト再試行 │

│ │───────────────────▶│

│ │ 200 + データ │

│ │◀───────────────────│

│ レンダリング │ │

│◀─────────────────│ │

ログアウトフロー

┌──────────┐ ┌──────────────┐ ┌──────────────┐ ┌──────────┐

│ Browser │ │ Frontend │ │ Backend │ │ IdP │

└────┬─────┘ └──────┬───────┘ └──────┬───────┘ └────┬─────┘

│ ログアウトクリック │ │ │

│─────────────────▶│ │ │

│ │ POST /auth/logout │ │

│ │───────────────────▶│ │

│ │ │ Revoke Token │

│ │ │─────────────────▶│

│ │ Set-Cookie: │ │

│ │ access_token="" │ │

│ │ Max-Age=0 │ │

│ │◀───────────────────│ │

│ クッキー削除、 │ │ │

│ ログインページへ │ │ │

│◀─────────────────│ │ │

> 核心ポイント:バックエンドが**HttpOnly Cookie**でトークンを管理すると、フロントエンドのJavaScriptはトークンに直接アクセスできません。これがXSS攻撃を防御する最も効果的な戦略です。

ブラウザストレージ別アクセス特性

トークンをどこに保存するかは、セキュリティと利便性のトレードオフです。各ストレージの特性を正確に理解して正しい選択をする必要があります。

| ストレージ | JSアクセス | サーバー自動送信 | XSS脆弱 | CSRF脆弱 |

| ------------------- | ---------- | ---------------- | ------- | -------- |

| HttpOnly Cookie | 不可 | あり | 安全 | あり |

| Non-HttpOnly Cookie | 可能 | あり | 脆弱 | あり |

| localStorage | 可能 | なし | 脆弱 | 安全 |

| sessionStorage | 可能 | なし | 脆弱 | 安全 |

| Memory(JS変数) | 可能 | なし | 一部 | 安全 |

**各ストレージの詳細分析:**

- **HttpOnly Cookie**:JavaScriptからアクセス不可能なのでXSSに安全です。ただし、ブラウザがすべてのリクエストに自動的にクッキーを添付するため、CSRF攻撃に脆弱です。**SameSite属性**と**CSRFトークン**を必ず併用してください。

- **Non-HttpOnly Cookie**:`document.cookie`でアクセス可能なため、XSSとCSRFの両方に脆弱です。可能な限り使用しないでください。

- **localStorage**:タブを閉じてもデータが保持されます。サーバーに自動送信されないのでCSRFには安全ですが、XSS攻撃でトークンが窃取される可能性があります。

- **sessionStorage**:タブ単位で隔離され、タブを閉じると削除されます。セキュリティ特性はlocalStorageと同じです。

- **Memory(JS変数)**:ページ更新時に消滅します。XSSに完全に安全ではありません(実行中のスクリプトがアクセス可能)が、攻撃難易度が高いです。**Silent Refresh**と組み合わせると良い戦略になります。

> 実践推奨:**Access TokenはHttpOnly Cookie**に、**CSRF防御はSameSite=Lax + CSRFトークンの二重適用**。Refresh TokenもHttpOnly Cookieに保存し、Pathを`/auth/refresh`に制限してください。

シリーズ目次

このシリーズは全5編で構成されています。このインデックスページで共通概念を学んだ後、各フレームワーク別の実践実装に移動してください。

| 編 | タイトル | 核心内容 |

| --- | --------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- |

| 0編 | **現在の記事(インデックス)** | 認証フロー全体マップ、共通概念の整理 |

| 1編 | [Spring Boot](/blog/architecture/2026-03-08-sso-cookie-jwt-auth-spring-boot) | SecurityFilterChain、JWTフィルター、CORS設定、CSRF防御 |

| 2編 | [Django](/blog/architecture/2026-03-08-sso-cookie-jwt-auth-django) | DRF + SimpleJWT、SessionMiddleware、django-cors-headers |

| 3編 | [React](/blog/architecture/2026-03-08-sso-cookie-jwt-auth-react) | Axiosインターセプター、Silent Refresh、Protected Route |

| 4編 | [Next.js](/blog/architecture/2026-03-08-sso-cookie-jwt-auth-nextjs) | Middleware、Server Actions、SSRクッキー伝達、next-auth |

| 5編 | [統合実践編 — SSO/OIDC + ハイブリッドアーキテクチャ](/blog/architecture/2026-03-08-sso-cookie-jwt-auth-hybrid-architecture) | Keycloak/Okta連携、BFFパターン、マルチサービスSSO |

**推奨読書順序:**

1. このインデックス記事で全体フローを把握します。

2. 自分が使用するバックエンドフレームワーク編(1編または2編)を読みます。

3. フロントエンド編(3編または4編)を読みます。

4. 5編で全体を統合するアーキテクチャを学習します。

セキュリティチェックリスト(シリーズ共通)

フレームワークに関係なく、すべての認証システムに適用すべきセキュリティ項目です。デプロイ前に必ず確認してください。

クッキー設定

- [ ] Access Tokenクッキーに`HttpOnly`属性が設定されているか?

- [ ] すべての認証クッキーに`Secure`属性が設定されているか?

- [ ] `SameSite`属性がサービスアーキテクチャに合わせて設定されているか?

- [ ] Refresh Tokenクッキーの`Path`が更新エンドポイントに制限されているか?

- [ ] クッキーの`Max-Age`が適切な時間に設定されているか?

- [ ] クッキーの`Domain`が必要な範囲にのみ制限されているか?

トークン管理

- [ ] Access Tokenの有効期限が十分に短いか?(推奨:5〜15分)

- [ ] Refresh Tokenの有効期限が設定されているか?(推奨:7〜30日)

- [ ] Refresh Token Rotationが実装されているか?

- [ ] 窃取されたRefresh Tokenを無効化できるメカニズムがあるか?

- [ ] JWT署名にRS256またはES256非対称アルゴリズムを使用しているか?

- [ ] JWTの`iss`、`aud`、`exp`クレームをすべて検証しているか?

CSRF防御

- [ ] 状態変更リクエスト(POST、PUT、DELETE)でCSRFトークンを検証しているか?

- [ ] CSRFトークンがリクエストごとまたはセッションごとに更新されるか?

- [ ] `SameSite`クッキー属性とCSRFトークンを二重に適用しているか?

CORS設定

- [ ] `Access-Control-Allow-Origin`にワイルドカード(`*`)を使用していないか?

- [ ] `Access-Control-Allow-Credentials: true`が設定されているか?

- [ ] 許可するOriginリストがホワイトリストで管理されているか?

- [ ] Preflightリクエスト(OPTIONS)が認証なしで通過するように設定されているか?

転送セキュリティ

- [ ] すべての通信がHTTPSで行われているか?

- [ ] HSTS(HTTP Strict Transport Security)ヘッダーが設定されているか?

- [ ] TLS 1.2以上を使用しているか?

ログアウト

- [ ] ログアウト時にサーバー側のセッション/トークンが無効化されるか?

- [ ] ログアウト時にすべての認証クッキーが削除されるか?

- [ ] SSO環境でSingle Logout(SLO)が実装されているか?

よくあるバグと誤解

誤解1:「JWTは暗号化されている」

JWTは**署名(Signed)**されているだけで**暗号化(Encrypted)**されていません。Base64URLエンコーディングは暗号化ではありません。誰でもPayloadをデコードして内容を読むことができます。

JWT Payloadのデコード(誰でも可能)

echo "eyJzdWIiOiJ1c2VyMTIzIn0" | base64 -d

出力: {"sub":"user123"}

機密情報(パスワード、社会保障番号など)をJWT Payloadに絶対に入れないでください。本当に暗号化が必要な場合はJWE(JSON Web Encryption)を使用してください。

誤解2:「localStorageにJWTを保存しても大丈夫」

SPAフレームワークの多くのチュートリアルが`localStorage`にJWTを保存する例を示しています。これはXSS攻撃に脆弱です。サードパーティライブラリの1つの脆弱性だけでトークンが窃取される可能性があります。

// 危険なパターン

localStorage.setItem('token', jwt)

// 安全なパターン:HttpOnly Cookieを使用(サーバーで設定)

// フロントエンドはトークンを直接扱わない

誤解3:「SameSite=LaxならCSRF攻撃は完全に防御される」

`SameSite=Lax`はほとんどのCSRFを防御しますが**完全ではありません**。クロスサイトのGETリクエストにはクッキーが送信されます。GETリクエストで状態を変更するAPIがある場合、依然として脆弱です。

GET /api/users/delete?id=123 ← SameSite=Laxでも防御不可!

→ 状態変更は必ずPOST/PUT/DELETEで設計してください

誤解4:「Refresh TokenはAccess Tokenより安全」

Refresh Tokenは長期間有効であるため、窃取されるとAccess Tokenより**さらに危険**です。Refresh Tokenが窃取されると、攻撃者が無限に新しいAccess Tokenを発行できます。

**防御戦略:**

- Refresh Token Rotation:更新時に以前のトークンを即座に無効化

- Token Family追跡:すでに使用されたRefresh Tokenが再使用されたら、そのFamily全体を無効化

- Refresh TokenをHttpOnly Cookieに保存しPath制限

誤解5:「CORSがサーバーを保護してくれる」

CORSは**ブラウザのポリシー**です。`curl`、Postman、サーバー間通信ではCORSは適用されません。CORSは悪意のあるWebサイトがユーザーのブラウザを利用してAPIを呼び出すことを防ぐだけで、API自体を保護するものではありません。

CORSに関係なく動作

curl -X POST https://api.myservice.com/data \

-H "Cookie: access_token=stolen_token"

→ サーバー側のトークン検証が必ず必要です

よくあるバグ:トークン更新のレースコンディション

複数のAPIリクエストが同時に401を受け取ると、Refreshリクエストも複数回発生します。Refresh Token Rotationを使用している場合、最初のリクエストのみ成功し、残りは失敗します。

// 解決:更新リクエストを1つにまとめるパターン

let refreshPromise = null

async function refreshToken() {

if (refreshPromise) return refreshPromise // すでに更新中なら待機

refreshPromise = axios.post('/auth/refresh').finally(() => {

refreshPromise = null

})

return refreshPromise

}

参考資料

このシリーズの執筆時に参考にした公式ドキュメントと標準仕様です。認証システムを設計する際に必ず原文を確認してください。

標準仕様(RFC)

1. [RFC 7519 — JSON Web Token (JWT)](https://datatracker.ietf.org/doc/html/rfc7519) — JWT標準仕様。クレーム、署名、検証手順を定義

2. [RFC 6749 — OAuth 2.0 Authorization Framework](https://datatracker.ietf.org/doc/html/rfc6749) — OAuth 2.0コアフレームワーク。Grant Typeごとのフローを定義

3. [RFC 6750 — OAuth 2.0 Bearer Token Usage](https://datatracker.ietf.org/doc/html/rfc6750) — Bearer Token送信方法(Authorizationヘッダー、クエリパラメータなど)

4. [RFC 7517 — JSON Web Key (JWK)](https://datatracker.ietf.org/doc/html/rfc7517) — 公開鍵配布のためのJWK Set標準

5. [RFC 6265 — HTTP State Management Mechanism (Cookie)](https://datatracker.ietf.org/doc/html/rfc6265) — HTTPクッキー標準仕様

OpenID Connect

6. [OpenID Connect Core 1.0](https://openid.net/specs/openid-connect-core-1_0.html) — OAuth 2.0上に認証(Authentication)レイヤーを追加した標準

セキュリティガイドライン

7. [OWASP — Session Management Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html) — セッション管理セキュリティのベストプラクティス

8. [OWASP — JSON Web Token Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/JSON_Web_Token_for_Java_Cheat_Sheet.html) — JWTセキュリティチェックリスト

9. [OWASP — Cross-Site Request Forgery Prevention](https://cheatsheetseries.owasp.org/cheatsheets/Cross-Site_Request_Forgery_Prevention_Cheat_Sheet.html) — CSRF防御戦略

フレームワーク公式ドキュメント

10. [MDN — HTTP Cookies](https://developer.mozilla.org/ja/docs/Web/HTTP/Cookies) — クッキー属性(SameSite、HttpOnly、Secureなど)の詳細説明

11. [Spring Security — OAuth 2.0 Resource Server](https://docs.spring.io/spring-security/reference/servlet/oauth2/resource-server/index.html) — Spring Boot JWT認証公式ガイド

12. [Django REST Framework — Authentication](https://www.django-rest-framework.org/api-guide/authentication/) — DRF認証メカニズム公式ドキュメント

13. [Next.js — Authentication](https://nextjs.org/docs/app/building-your-application/authentication) — Next.js App Routerベースの認証実装ガイド

14. [MDN — CORS](https://developer.mozilla.org/ja/docs/Web/HTTP/CORS) — Cross-Origin Resource Sharing完全ガイド

현재 단락 (1/196)

Web認証はシンプルではありません。「ログイン機能を1つ作ればいい」と考えがちですが、実践では以下のような疑問が次々と湧いてきます。

작성 글자: 0원문 글자: 9,616작성 단락: 0/196