Sensitive cookie set without the Secure flag

Sensitive cookie set without the Secure flag

Description

A cookie containing sensitive information, such as a session ID or login state, may be sent over unencrypted HTTP if the Secure flag is missing. An attacker able to intercept network traffic, for example on public Wi-Fi, may steal the value and use the session cookie to impersonate the user.

Potential impact

  • A session cookie issued over HTTPS may later be sent over HTTP and intercepted, enabling session hijacking.
  • A stolen session ID may let an attacker act as the user to view account data, change settings or make payments.
  • Additional sensitive values in the cookie, such as permission information or user identifiers, may also be exposed.

Remediation

  • Set Secure: true on all session and authentication cookies.
  • Use HTTPS throughout the service. Redirecting HTTP to HTTPS cannot protect a cookie already sent in the HTTP request.
  • Also set HttpOnly: true to reduce cookie-value theft through JavaScript. It does not prevent XSS itself.
  • Where possible, use Secure by default for nonsensitive cookies too.
  • Maintain the required security attributes in shared cookie creation and deletion helpers. To delete a cookie, match its original name, Domain and Path.

Examples

Before

go
package main

import (
    "net/http"
)

// Before: missing Secure flag
func setSessionCookie(w http.ResponseWriter, sessionID string) {
    // Login session cookie without Secure or HttpOnly
    cookie := http.Cookie{
        Name:  "SESSIONID",
        Value: sessionID,
        Path:  "/",
        // Secure defaults to false
        // HttpOnly defaults to false
    }

    // This cookie may also be sent in HTTP requests
    http.SetCookie(w, &cookie)
}

After

go
package main

import (
    "net/http"
    "time"
)

// After: explicitly set Secure and HttpOnly
func setSessionCookie(w http.ResponseWriter, sessionID string) {
    cookie := http.Cookie{
        Name:     "SESSIONID",
        Value:    sessionID,
        Path:     "/",
        Secure:   true,          // Send only over HTTPS
        HttpOnly: true,          // Not readable by JavaScript
        SameSite: http.SameSiteLaxMode,
        Expires:  time.Now().Add(30 * time.Minute),
    }

    http.SetCookie(w, &cookie)
}

// Retain Secure/HttpOnly when deleting the cookie
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)
}

Explanation:

  • Before: setSessionCookie creates the sensitive SESSIONID cookie without Secure: true, so a browser may send it over HTTP where a network attacker can intercept it. Without HttpOnly, an XSS vulnerability may also let JavaScript read the value.
  • After: Secure: true limits transmission to HTTPS, and HttpOnly: true prevents browser JavaScript from reading the cookie value. The deletion example uses the same name and Path, and both examples omit Domain. That matching identity is needed to remove the original cookie; Secure and HttpOnly are separate protection attributes.

References