Sensitive Cookie in HTTPS Session Without 'Secure' Attribute

Description

Sensitive Cookie in HTTPS Session Without 'Secure' Attribute occurs when a cookie containing sensitive data (such as session tokens, authentication tokens, or user credentials) is set without the Secure flag. Without this flag, the browser will send the cookie over unencrypted HTTP connections, even if the cookie was originally set over HTTPS. Attackers performing man-in-the-middle attacks can intercept these cookies when users access any HTTP resource, even on different sites.

Risk

Missing Secure flag on sensitive cookies enables cookie theft through network interception. Even on sites that enforce HTTPS, browsers will send non-secure cookies over HTTP if the user visits any HTTP resource (including images or redirects). Attackers on shared networks (WiFi hotspots, corporate networks) can easily capture these cookies. Session hijacking through cookie theft remains one of the most common web attacks. The attack requires minimal skill with tools like Wireshark or Firesheep.

Solution

Always set the Secure flag on cookies containing sensitive data. Use HTTPS for all application resources. Implement HTTP Strict Transport Security (HSTS) to prevent HTTP downgrade attacks. Set appropriate cookie attributes: Secure, HttpOnly, SameSite. Use framework defaults that apply security attributes automatically. Audit cookie settings regularly. Consider using __Host- or __Secure- cookie prefixes for additional protection.

Common Consequences

ImpactDetails
ConfidentialityScope: Session Theft

Session cookies transmitted over HTTP can be intercepted, enabling session hijacking.
Access ControlScope: Account Takeover

Stolen authentication cookies allow attackers to impersonate users.
IntegrityScope: Unauthorized Actions

Attackers with stolen sessions can perform actions as the victim user.

Example Code + Solution Code

Vulnerable Code

# VULNERABLE: Session cookie without Secure flag
from flask import Flask, session

app = Flask(__name__)
app.secret_key = 'secret'

# No secure cookie configuration!

@app.route('/login')
def login():
    session['user_id'] = user.id
    # Cookie sent without Secure flag
    return redirect('/dashboard')

# VULNERABLE: Manual cookie without Secure
from flask import make_response

@app.route('/set-token')
def set_token():
    response = make_response('Token set')
    # Missing Secure flag!
    response.set_cookie('auth_token', token, httponly=True)
    return response
// VULNERABLE: Servlet cookie without Secure
@WebServlet("/login")
public class LoginServlet extends HttpServlet {

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        // Authenticate user...

        Cookie sessionCookie = new Cookie("SESSIONID", sessionId);
        sessionCookie.setHttpOnly(true);
        // Missing: sessionCookie.setSecure(true);

        response.addCookie(sessionCookie);
        response.sendRedirect("/dashboard");
    }
}

// VULNERABLE: Spring session without secure cookies
@Configuration
public class SessionConfig {
    // No cookie configuration - defaults may not be secure
}
// VULNERABLE: Express session without secure cookie
const session = require('express-session');

app.use(session({
    secret: 'keyboard cat',
    resave: false,
    saveUninitialized: true,
    cookie: {
        httpOnly: true
        // Missing: secure: true
    }
}));

// VULNERABLE: Manual cookie without secure flag
app.get('/set-cookie', (req, res) => {
    res.cookie('authToken', token, {
        httpOnly: true
        // Missing: secure: true
    });
    res.send('Cookie set');
});
// VULNERABLE: PHP session without secure flag
<?php
session_start();  // Uses default settings
$_SESSION['user_id'] = $user_id;

// VULNERABLE: setcookie without Secure
setcookie('auth_token', $token, [
    'httponly' => true,
    // 'secure' => true is missing!
    'path' => '/'
]);
?>

Fixed Code

# SAFE: Flask with secure cookie configuration
from flask import Flask, session

app = Flask(__name__)
app.secret_key = os.urandom(32)

# Configure secure cookies
app.config.update(
    SESSION_COOKIE_SECURE=True,      # Secure flag
    SESSION_COOKIE_HTTPONLY=True,    # HttpOnly flag
    SESSION_COOKIE_SAMESITE='Lax',   # SameSite attribute
    SESSION_COOKIE_NAME='__Host-session'  # Cookie prefix for extra security
)

@app.route('/login')
def login():
    session['user_id'] = user.id
    # Cookie now has Secure flag
    return redirect('/dashboard')

# SAFE: Manual cookie with all security attributes
@app.route('/set-token')
def set_token():
    response = make_response('Token set')
    response.set_cookie(
        'auth_token',
        token,
        secure=True,         # Only sent over HTTPS
        httponly=True,       # Not accessible via JavaScript
        samesite='Strict',   # Not sent in cross-site requests
        max_age=3600,        # 1 hour expiry
        path='/'
    )
    return response

# SAFE: Force HTTPS and HSTS
@app.before_request
def enforce_https():
    if not request.is_secure and not app.debug:
        return redirect(request.url.replace('http://', 'https://'), code=301)

@app.after_request
def add_security_headers(response):
    # HSTS header - force HTTPS for 1 year
    response.headers['Strict-Transport-Security'] = 'max-age=31536000; includeSubDomains; preload'
    return response
// SAFE: Servlet with secure cookies
@WebServlet("/login")
public class SecureLoginServlet extends HttpServlet {

    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {

        // Authenticate user...

        Cookie sessionCookie = new Cookie("SESSIONID", sessionId);
        sessionCookie.setSecure(true);      // Only HTTPS
        sessionCookie.setHttpOnly(true);    // No JavaScript access
        sessionCookie.setPath("/");
        sessionCookie.setMaxAge(3600);      // 1 hour

        // SameSite requires Servlet 4.0+ or header manipulation
        response.setHeader("Set-Cookie",
            sessionCookie.getName() + "=" + sessionCookie.getValue() +
            "; Secure; HttpOnly; SameSite=Strict; Path=/; Max-Age=3600");

        response.sendRedirect("/dashboard");
    }
}

// SAFE: Spring Security configuration
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .requiresChannel()
                .anyRequest().requiresSecure()  // Force HTTPS
            .and()
            .headers()
                .httpStrictTransportSecurity()
                    .includeSubDomains(true)
                    .maxAgeInSeconds(31536000);
    }

    @Bean
    public CookieSerializer cookieSerializer() {
        DefaultCookieSerializer serializer = new DefaultCookieSerializer();
        serializer.setCookieName("SESSION");
        serializer.setUseSecureCookie(true);      // Secure flag
        serializer.setUseHttpOnlyCookie(true);    // HttpOnly flag
        serializer.setSameSite("Strict");         // SameSite attribute
        serializer.setCookiePath("/");
        return serializer;
    }
}

// SAFE: Spring Boot application.properties
// server.servlet.session.cookie.secure=true
// server.servlet.session.cookie.http-only=true
// server.servlet.session.cookie.same-site=strict
// SAFE: Express with secure session cookies
const session = require('express-session');

app.use(session({
    secret: process.env.SESSION_SECRET,
    resave: false,
    saveUninitialized: false,
    name: '__Host-sessionId',  // Cookie prefix
    cookie: {
        secure: true,           // Only sent over HTTPS
        httpOnly: true,         // Not accessible via JavaScript
        sameSite: 'strict',     // Not sent in cross-site requests
        maxAge: 3600000,        // 1 hour
        path: '/'
    }
}));

// SAFE: Manual secure cookie
app.get('/set-cookie', (req, res) => {
    res.cookie('authToken', token, {
        secure: true,
        httpOnly: true,
        sameSite: 'strict',
        maxAge: 3600000,
        path: '/'
    });
    res.send('Cookie set');
});

// SAFE: Force HTTPS with helmet
const helmet = require('helmet');

app.use(helmet.hsts({
    maxAge: 31536000,
    includeSubDomains: true,
    preload: true
}));

// Redirect HTTP to HTTPS
app.use((req, res, next) => {
    if (!req.secure && req.get('x-forwarded-proto') !== 'https') {
        return res.redirect(301, `https://${req.get('host')}${req.url}`);
    }
    next();
});
// SAFE: PHP with secure session cookies
<?php
// Configure session before starting
ini_set('session.cookie_secure', 1);      // Secure flag
ini_set('session.cookie_httponly', 1);    // HttpOnly flag
ini_set('session.cookie_samesite', 'Strict');  // SameSite attribute
ini_set('session.use_only_cookies', 1);   // Only use cookies
ini_set('session.use_strict_mode', 1);    // Strict session mode

session_start();
$_SESSION['user_id'] = $user_id;

// SAFE: Manual cookie with all attributes
setcookie('auth_token', $token, [
    'expires' => time() + 3600,
    'path' => '/',
    'secure' => true,       // Only HTTPS
    'httponly' => true,     // No JavaScript
    'samesite' => 'Strict'  // No cross-site
]);

// Or using header for full control
header('Set-Cookie: auth_token=' . $token . '; Secure; HttpOnly; SameSite=Strict; Path=/; Max-Age=3600');
?>

Exploited in the Wild

Firesheep (2010)

Firesheep was a Firefox extension that demonstrated the ease of hijacking sessions on unencrypted WiFi networks by capturing cookies without the Secure flag from major sites like Facebook and Twitter.

SSL Strip Attacks

Attackers use SSL stripping to downgrade HTTPS connections to HTTP, capturing cookies that lack the Secure flag even on sites that normally use HTTPS.

Public WiFi Session Hijacking

Numerous real-world attacks on public WiFi networks have exploited missing Secure flags to steal session cookies from banking, email, and social media sites.


Tools to test/exploit


CVE Examples


References

  1. MITRE. "CWE-614: Sensitive Cookie in HTTPS Session Without 'Secure' Attribute." https://cwe.mitre.org/data/definitions/614.html

  2. OWASP. "Secure Cookie Attribute." https://owasp.org/www-community/controls/SecureCookieAttribute