Go言語でのセッション管理:『徳丸本』に学ぶセッションIDの自作禁止と固定化攻撃対策
Webアプリケーション開発、特に認証周りの実装において「セッションIDをどのように生成・管理するか」はセキュリティの生命線です。
名著『体系的に学ぶ 安全なWebアプリケーションの作り方』(通称:徳丸本)では、 「セッションIDを自作してはならない」 と強く警告されています。
今回はGo言語を例に、なぜ自作がNGなのか、そしてライブラリを使っても残る「セッション固定化攻撃」のリスクと実装策について整理します。
1. なぜセッションIDを自作してはいけないのか
セッションIDには、第三者に推測されないための「十分な桁数」と「ランダム性(エントロピー)」が求められます。
もし開発者が time.Now().Unix() や連番、あるいは脆弱な乱数生成器(Goで言う math/rand)を使ってIDを生成してしまうと、攻撃者に次のIDを予測され、他人のセッションを乗っ取られる(セッションハイジャック)リスクが激増します。
Goでの正解:信頼できるライブラリに任せる
Goの標準ライブラリにはセッション管理機構がないため、暗号論的擬似乱数生成器(crypto/rand)を内部で適切に使用している検証済みのライブラリを使用します。
デファクトスタンダードである gorilla/sessions を使うのが一般的です。
// 悪い例:自前で乱数を作る(予測可能になるリスクが高い)
// func generateSessionID() string { ... }
// 良い例:gorilla/sessionsに任せる
// 内部的にcrypto/randが使われ、予測不可能なIDが生成される
var store = sessions.NewCookieStore([]byte("very-secret-key"))
それでも、ライブラリを使っても防げないケースがあることも紹介します。
2. ライブラリを使っても防げない「セッション固定化攻撃」
「予測不可能なID」を使っていれば安全かというと、そうではありません。 セッション固定化攻撃(Session Fixation) という手法が存在するからです。
詳細な攻撃フローは、上記の情報処理推進機構(IPA)の公式サイトで確認してみてください。
攻撃のメカニズム
- 攻撃者がサイトにアクセスし、有効なセッションID(例: SID=123)を取得する。
- 攻撃者が被害者に http://example.com/login?SID=123 のような罠リンクを踏ませ、そのIDを強制的にブラウザにセットさせる(※Cookieへの注入手法は様々)。
- 被害者がそのID(SID=123)を持ったままログインに成功する。
- 攻撃者も SID=123 を知っているため、被害者のアカウントでログイン状態に入れてしまう。
パターン1:攻撃の成立フロー(脆弱性がある場合)

パターン2:対策後のフロー(IDローテーション)

これを防ぐための鉄則が、 「認証(ログイン)成功時に、セッションIDをローテーション(再生成)する」 ことです。
3. Goによるセッションローテーションの実装
gorilla/sessions には「1行でローテーションするメソッド」が標準ではないため、 「既存セッションの破棄」→「新規セッションの作成」 を明示的に行う必要があります。
以下は、ログインハンドラ内でセッションIDを刷新する実装例です。
package main
import (
"net/http"
"github.com/gorilla/sessions"
)
var store = sessions.NewCookieStore([]byte("secret-key"))
func loginHandler(w http.ResponseWriter, r *http.Request) {
// --- (1) ユーザー認証処理(ID/Pass確認など) ---
// if !isAuthenticated { return }
// --- (2) セッション固定化攻撃対策:IDのローテーション ---
// A. 古いセッションを取得
oldSession, _ := store.Get(r, "mysession")
// B. 古いセッションを無効化(MaxAgeをマイナスにしてCookie削除を指示)
oldSession.Options.MaxAge = -1
oldSession.Save(r, w)
// C. 新しいセッションを作成
// store.New() を呼ぶことで強制的に新規セッションインスタンスを作る
newSession, _ := store.New(r, "mysession")
// --- (3) 新しいセッションの設定 ---
newSession.Values["user_id"] = "user123" // ユーザー情報をセット
// セキュリティ設定(必須)
newSession.Options.HttpOnly = true // XSS対策:JSからのアクセス禁止
newSession.Options.Secure = true // 盗聴対策:HTTPSのみ許可
newSession.Options.SameSite = http.SameSiteLaxMode
// 保存(ここで新しいセッションIDが発行され、Set-Cookieされる)
newSession.Save(r, w)
}
まとめ
セッション管理を安全に行うためのポイントは以下の3点に集約されます。
- 自作しない : crypto/rand を適切に扱うライブラリ(gorilla/sessionsなど)を使用し、予測不可能性を担保する。
- 漏洩対策 : HttpOnly(XSS対策)と Secure(盗聴対策)属性を必ず付与する。
- 固定化対策 : ログイン成功のタイミングで、必ずセッションIDを 再生成(ローテーション) する。
フレームワークやライブラリを使っていても、「ローテーション」は開発者が明示的に呼び出さないといけないケースが多いため、実装漏れがないかコードレビューでの重要チェックポイントとなります。