Mímisbrunnr知恵の泉

← サイバーセキュリティ 一覧

🎓 レベル:標準 | 重要度:A(必須) 📎 前提:認証の基礎(パスワード保存とMFA)

要点(BLUF)

概念:ログイン状態をどう運ぶか

ログインは一瞬ですが、その後のリクエストでも「この人は認証済み」と分からねばなりません。HTTP 自体は状態を覚えないので、状態を運ぶ仕組みが必要です。2方式あります。

仕組み:セッション vs JWT

観点セッション(サーバ保持)JWT(自己完結)
状態の所在サーバ(ストア)トークン内(クライアント)
検証方法ストア照合署名検証
失効容易(サーバで消す)難しい(期限切れ待ち+失効リスト)
スケールストア共有が要る状態共有不要で水平展開しやすい
主な注意点ID 漏えい・固定化署名検証・保管・失効

JWT は3部構成(ヘッダ.ペイロード.署名)で、ヘッダとペイロードはBase64 でエンコードされているだけ=暗号化ではない点が重要です。誰でも中身を読めます。守っているのは機密性ではなく完全性と真正性(署名、デジタル署名と証明書(PKI))です。だから JWT に秘密情報を入れてはいけません。

flowchart LR
    LOGIN["ログイン成功"] --> ISSUE["サーバがJWTを発行(署名つき)"]
    ISSUE --> STORE["クライアントが保管(HttpOnly Cookie 推奨)"]
    STORE -->|"以降のリクエストに添付"| VERIFY{"サーバが署名と期限を検証"}
    VERIFY -->|"正当"| ALLOW["処理を許可"]
    VERIFY -->|"改ざん・期限切れ・alg不正"| DENY["拒否"]

防御側の使い方/設定

なぜ安全か:署名が「改ざんできない預かり証」を作る

JWT が状態をクライアントに預けても安全なのは、署名により中身を1文字でも変えると検証が失敗するからです(完全性)。さらに署名鍵を持つのは発行サーバだけなので、第三者は正規トークンを作れません(真正性)。ただしこれは「検証側が必ず署名を確かめ、許可アルゴリズムを固定している」ことが前提です。検証を省く・alg=none を受理する実装は、この保証を自ら捨てています。

security-study/labs/jwt_verify_demo.py の実行結果(抜粋):

=== 1. 正規トークンは検証できる ===
claims = {'sub': 'user-123', 'role': 'viewer', 'exp': 1782636475}
=== 2. ペイロード改ざん -> 署名検証で拒否 ===
改ざん拒否 OK -> InvalidSignatureError
=== 3. 期限切れトークン -> 拒否 ===
期限切れ拒否 OK -> ExpiredSignatureError

改ざんは InvalidSignatureError、期限切れは ExpiredSignatureError で確実に拒否されます。

仕組みの直観

セッションはクロークの預かり札です。札(セッション ID)自体に意味はなく、番号を見せると店が控え(サーバの状態)と照合して荷物を返す。JWT は改ざん防止フィルム付きの会員証で、券面に会員情報が印刷され、偽造防止の封(署名)が押してある。店は控えを持たず、封が本物かだけ確かめます。封の確認をサボれば偽造証を通してしまいます。

⚠️ よくある誤解・設定ミス

対応 lab

関連