Session
Sessionとは、ユーザーごとの状態をサーバー側で保持する仕組みです。Webは本来「ステートレス」(通信が終わると状態を保持しない)なプロトコルであるため、ユーザーがログイン中かどうかなどの情報を保持するためにSessionが使われます。
Sessionの仕組み
- ユーザーがログインすると、サーバー側でSessionを生成し、SessionIDを発行します
- SessionIDはCookieやURLパラメータを通じてクライアントに渡されます
- 次回以降のリクエストで、SessionIDが送信されることで、サーバー側でユーザーを識別できます
Sessionの特徴
-
サーバー側にデータを保存
- Sessionデータはサーバー上に保持されます(例: メモリやデータベース)
-
クライアントの負担が少ない
- クライアント側ではSessionIDだけを保持
-
セキュリティが高い
- Sessionデータはサーバー側に保存されるため、直接改ざんされにくい
Sessionの欠点
- サーバーのリソースを消費する
- ロードバランサーを使用する場合、Session管理が複雑になる(Sessionの共有が必要)
Cookie
Cookieは、Webブラウザにデータを保存する仕組みです。ユーザー識別や状態管理のために使われ、SessionIDをクライアントに渡す手段としても活用されます。
Cookieの仕組み
- サーバーがクライアントにレスポンスを返す際に、HTTPヘッダーにCookieを付与します
- クライアント(ブラウザ)はCookieを保存します
- 次回以降のリクエストで、保存したCookieをHTTPヘッダーに含めてサーバーに送信します
Cookieの特徴
-
クライアント側にデータを保存
- 状態や設定情報をブラウザに保持します
-
簡単に使用可能
- HTTPリクエストとレスポンスに付加するだけで利用できます
Cookieの用途
- SessionIDの保存
- ユーザー設定(テーマ、言語など)の保持
- トラッキング情報(広告や分析ツールで利用)
Cookieの制限
- 保存容量はブラウザごとに制限されている(通常4KB程度)
- 改ざんや盗聴のリスクがあるため、暗号化やセキュアな通信(HTTPS)が推奨されます
SessionとCookieの違い
項目 | Session | Cookie |
---|---|---|
データの保存場所 | サーバー側 | クライアント側 |
データ量の制限 | サーバーのリソースに依存 | 通常4KB程度 |
セキュリティ | 比較的高い(サーバー管理) | 改ざんや盗聴のリスクがある |
有効期限 | 通常ブラウザを閉じると終了 | 有効期限を設定可能 |
使用例 | ログイン情報、ショッピングカート | ユーザー設定、SessionIDの保存 |
Goサンプルコード
package main
import (
"fmt"
"net/http"
"github.com/gorilla/sessions"
)
// セッションストアの設定(Cookieストアを使用)
var store = sessions.NewCookieStore([]byte("your-secret-key"))
func loginHandler(w http.ResponseWriter, r *http.Request) {
if r.Method != http.MethodPost {
http.Error(w, "Invalid request method", http.StatusMethodNotAllowed)
return
}
// フォームデータからユーザー名を取得
username := r.FormValue("username")
if username == "" {
http.Error(w, "Username is required", http.StatusBadRequest)
return
}
// セッションを取得(新規作成含む)
session, _ := store.Get(r, "session-name")
// セッションにユーザー情報を保存
session.Values["username"] = username
session.Save(r, w) // セッションを保存
fmt.Fprintf(w, "Logged in as %s", username)
}
func profileHandler(w http.ResponseWriter, r *http.Request) {
// セッションを取得
session, _ := store.Get(r, "session-name")
// セッションからユーザー名を取得
username, ok := session.Values["username"].(string)
if !ok || username == "" {
http.Error(w, "Unauthorized", http.StatusUnauthorized)
return
}
fmt.Fprintf(w, "Welcome, %s!", username)
}
func logoutHandler(w http.ResponseWriter, r *http.Request) {
// セッションを取得
session, _ := store.Get(r, "session-name")
// セッションデータをクリア
session.Options.MaxAge = -1 // クッキーの有効期限を無効にする
session.Save(r, w) // セッションを保存
fmt.Fprintln(w, "Logged out")
}
func main() {
http.HandleFunc("/login", loginHandler)
http.HandleFunc("/profile", profileHandler)
http.HandleFunc("/logout", logoutHandler)
fmt.Println("Server started at :8080")
http.ListenAndServe(":8080", nil)
}
/loginにPOST
Logged in as hogehoge
/profileにGET
Welcome, hogehoge!
/logoutにGET
Logged out
SessionとCookieのセキュリティ対策
HTTPSを使用する
- 暗号化された通信を利用し、SessionIDやCookieが盗聴されるリスクを軽減します
SessionIDの保護
- Sessionハイジャックを防ぐため、SessionIDは予測困難なものにする
- 定期的にSessionIDを更新(Session固定攻撃の防止)
CookieのHttpOnly属性
- JavaScriptからアクセスできないようにすることで、XSS攻撃から保護します
CookieのSecure属性
- HTTPS通信時のみCookieを送信
CSRFトークンの活用
- Sessionを利用するリクエストにはCSRFトークンを含める