説明
セッションIDやログイン状態などの機密情報を含むCookieに Secure フラグがないと、暗号化されていないHTTPでも送信される可能性があります。公衆Wi-Fiなどで通信を傍受できる攻撃者が値を盗み、そのセッションCookieでユーザーになりすますおそれがあります。
想定される影響
- HTTPSで発行したセッションCookieが後からHTTPで送られ、傍受によるセッションの乗っ取りにつながる可能性があります。
- 盗まれたセッションIDでユーザーになりすまされ、アカウント情報の閲覧、設定変更、決済などを行われるおそれがあります。
- 権限情報やユーザー識別子など、Cookieに含まれる追加の機密情報も漏えいする可能性があります。
対処方法
- すべてのセッション・認証Cookieに
Secure: trueを設定してください。 - サービス全体でHTTPSを使ってください。HTTPからHTTPSへリダイレクトしても、最初のHTTPリクエストで送られたCookieは保護できません。
HttpOnly: trueも設定し、JavaScriptによる値の窃取を抑えてください。XSS自体を防ぐ設定ではありません。- 可能なら機密ではないCookieにも、既定で
Secureを適用してください。 - Cookieの作成・削除用の共通関数で、必要な保護属性を維持してください。削除時には元のCookieの名前、
Domain、Pathと一致させてください。
例
変更前
go
package main
import (
"net/http"
)
// 変更前: Secureフラグなし
func setSessionCookie(w http.ResponseWriter, sessionID string) {
// ログインセッションCookieにSecureとHttpOnlyを設定していない
cookie := http.Cookie{
Name: "SESSIONID",
Value: sessionID,
Path: "/",
// Secureの既定値はfalse
// HttpOnlyの既定値はfalse
}
// HTTPリクエストでも送信される可能性がある
http.SetCookie(w, &cookie)
}
変更後
go
package main
import (
"net/http"
"time"
)
// 変更後: SecureとHttpOnlyを明示的に設定
func setSessionCookie(w http.ResponseWriter, sessionID string) {
cookie := http.Cookie{
Name: "SESSIONID",
Value: sessionID,
Path: "/",
Secure: true, // HTTPS接続だけで送信
HttpOnly: true, // JavaScriptから読み取り不可
SameSite: http.SameSiteLaxMode,
Expires: time.Now().Add(30 * time.Minute),
}
http.SetCookie(w, &cookie)
}
// 削除時もSecure/HttpOnlyを維持
func deleteSessionCookie(w http.ResponseWriter) {
cookie := http.Cookie{
Name: "SESSIONID",
Value: "",
Path: "/",
Secure: true,
HttpOnly: true,
Expires: time.Unix(0, 0),
MaxAge: -1,
}
http.SetCookie(w, &cookie)
}
解説:
- 変更前:
setSessionCookieが機密のSESSIONIDCookieをSecure: trueなしで作るため、HTTPで送られて傍受される可能性があります。HttpOnlyもなく、XSSがあるとJavaScriptから値を読まれるおそれがあります。 - 変更後:
Secure: trueでHTTPSだけに送信を限定し、HttpOnly: trueでブラウザーのJavaScriptから値を読めなくします。削除例では同じ名前とPathを使い、どちらもDomainを省略しています。元のCookieを削除するにはこの識別範囲の一致が必要です。SecureとHttpOnlyは別の保護属性です。