Skip to content

CWE-614: Sensitive Cookie Without 'Secure' Flag - Java

Overview

Sensitive Cookie Without 'Secure' Flag in Java web applications occurs when cookies containing sensitive data (session IDs, authentication tokens, CSRF tokens) are created without the secure attribute set to true. This allows cookies to be transmitted over unencrypted HTTP connections, exposing them to man-in-the-middle (MITM) attacks, network sniffing, session hijacking, and account compromise.

Common Java Vulnerability Scenarios:

  • Servlet cookies without setSecure(true)
  • Spring Boot cookies missing secure attribute
  • JAX-RS cookies without security flags
  • JSP session cookies transmitted over HTTP
  • Jakarta EE cookies with improper configuration
  • OAuth tokens in insecure cookies

Java Framework Cookie Security:

  • Servlet API: cookie.setSecure(true); cookie.setHttpOnly(true);
  • Spring Boot: server.servlet.session.cookie.secure=true
  • JAX-RS: NewCookie.Builder.newInstance().secure(true).httpOnly(true)
  • Jakarta EE: Cookie attributes in web.xml or programmatically

Primary Defence: Set secure=true, httpOnly=true, and sameSite=Strict on all cookies containing sensitive data, and enforce HTTPS in production.

Common Vulnerable Patterns

// VULNERABLE - Session cookie without secure flag
import javax.servlet.http.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
import java.util.UUID;

@WebServlet("/login")
public class LoginServlet extends HttpServlet {

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

        String username = request.getParameter("username");
        String password = request.getParameter("password");

        if (authenticateUser(username, password)) {
            String sessionToken = UUID.randomUUID().toString();

            // VULNERABLE - Cookie missing secure flag
            Cookie sessionCookie = new Cookie("JSESSIONID", sessionToken);
            sessionCookie.setMaxAge(3600);  // 1 hour
            sessionCookie.setHttpOnly(true);  // Good, but not enough
            sessionCookie.setPath("/");
            // Missing: sessionCookie.setSecure(true);

            response.addCookie(sessionCookie);
            response.getWriter().write("{\"status\": \"logged_in\"}");
        } else {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write("{\"error\": \"Invalid credentials\"}");
        }
    }

    private boolean authenticateUser(String username, String password) {
        // Authentication logic
        return true;
    }
}

Why this is vulnerable:

  • Cookie transmitted over HTTP
  • Susceptible to MITM attacks
  • Network sniffing can capture session token
  • Session hijacking possible

Spring Boot Without Secure Cookies

SecurityConfig.java
// VULNERABLE - Spring Boot application without secure cookie configuration

// application.properties - VULNERABLE
// server.servlet.session.cookie.secure=false  # BAD!
// server.servlet.session.cookie.http-only=true
// server.servlet.session.cookie.same-site=strict

package com.example.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.web.SecurityFilterChain;

@Configuration
public class VulnerableSecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
            )
            .formLogin(form -> form
                .loginPage("/login")
                .permitAll()
            );

        // VULNERABLE - Not configuring cookie security
        // Missing secure cookie configuration

        return http.build();
    }
}
LoginController.java
package com.example.controller;

import org.springframework.web.bind.annotation.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.util.UUID;

@RestController
@RequestMapping("/api")
public class LoginController {

    @PostMapping("/login")
    public LoginResponse login(
            @RequestParam String username,
            @RequestParam String password,
            HttpServletResponse response) {

        if (authenticateUser(username, password)) {
            String token = UUID.randomUUID().toString();

            // VULNERABLE - Custom cookie without secure flag
            Cookie authCookie = new Cookie("auth_token", token);
            authCookie.setMaxAge(3600);
            authCookie.setHttpOnly(true);
            authCookie.setPath("/");
            // Missing: authCookie.setSecure(true);

            response.addCookie(authCookie);

            return new LoginResponse("logged_in", username);
        }

        throw new RuntimeException("Invalid credentials");
    }

    private boolean authenticateUser(String username, String password) {
        return true;
    }

    static class LoginResponse {
        public String status;
        public String username;

        public LoginResponse(String status, String username) {
            this.status = status;
            this.username = username;
        }
    }
}

Why this is vulnerable:

  • Application properties don't set secure=true
  • Custom authentication cookies vulnerable
  • Spring session cookies transmitted over HTTP
  • Production deployment risk
// VULNERABLE - JAX-RS REST API with insecure cookies
package com.example.api;

import javax.ws.rs.*;
import javax.ws.rs.core.*;
import java.util.UUID;

@Path("/auth")
public class VulnerableAuthResource {

    @POST
    @Path("/login")
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Produces(MediaType.APPLICATION_JSON)
    public Response login(
            @FormParam("username") String username,
            @FormParam("password") String password) {

        if (authenticateUser(username, password)) {
            String sessionToken = UUID.randomUUID().toString();

            // VULNERABLE - NewCookie without secure flag
            NewCookie cookie = new NewCookie(
                "session_id",           // name
                sessionToken,           // value
                "/",                    // path
                null,                   // domain
                null,                   // comment
                3600,                   // maxAge
                false                   // secure - SHOULD BE TRUE!
            );

            return Response.ok()
                .entity("{\"status\": \"logged_in\"}")
                .cookie(cookie)
                .build();
        }

        return Response.status(Response.Status.UNAUTHORIZED)
            .entity("{\"error\": \"Invalid credentials\"}")
            .build();
    }

    private boolean authenticateUser(String username, String password) {
        return true;
    }
}

Why this is vulnerable:

  • NewCookie secure parameter set to false
  • Cookie sent over HTTP
  • REST API authentication compromised
  • Token interception possible
web.xml
<!-- VULNERABLE configuration -->
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                             http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <session-config>
        <session-timeout>30</session-timeout>
        <cookie-config>
            <http-only>true</http-only>
            <!-- VULNERABLE: secure not set to true -->
            <!-- <secure>true</secure> -->
            <same-site>Strict</same-site>
        </cookie-config>
    </session-config>

</web-app>
LoginServlet.java
package com.example.servlet;

import javax.servlet.http.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;

@WebServlet("/session-login")
public class SessionLoginServlet extends HttpServlet {

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

        String username = request.getParameter("username");
        String password = request.getParameter("password");

        if (authenticateUser(username, password)) {
            // VULNERABLE - Session cookie inherits web.xml config (no secure flag)
            HttpSession session = request.getSession(true);
            session.setAttribute("username", username);
            session.setAttribute("authenticated", true);
            session.setMaxInactiveInterval(1800);  // 30 minutes

            response.getWriter().write("{\"status\": \"logged_in\"}");
        } else {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write("{\"error\": \"Invalid credentials\"}");
        }
    }

    private boolean authenticateUser(String username, String password) {
        return true;
    }
}

Why this is vulnerable:

  • web.xml missing <secure>true</secure>
  • Session cookies transmitted over HTTP
  • Container-managed sessions vulnerable
  • Configuration error
// VULNERABLE - Remember-me functionality with insecure cookie
package com.example.auth;

import javax.servlet.http.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.Base64;

@WebServlet("/remember-login")
public class RememberMeLoginServlet extends HttpServlet {

    private static final SecureRandom secureRandom = new SecureRandom();

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

        String username = request.getParameter("username");
        String password = request.getParameter("password");
        boolean rememberMe = "true".equals(request.getParameter("remember_me"));

        if (authenticateUser(username, password)) {
            String sessionToken = generateSecureToken();

            // Session cookie (also vulnerable but short-lived)
            Cookie sessionCookie = new Cookie("session_id", sessionToken);
            sessionCookie.setMaxAge(3600);  // 1 hour
            sessionCookie.setHttpOnly(true);
            sessionCookie.setPath("/");
            // Missing: sessionCookie.setSecure(true);

            response.addCookie(sessionCookie);

            if (rememberMe) {
                String rememberToken = generateSecureToken();

                // VULNERABLE - Long-lived remember-me cookie without secure flag
                Cookie rememberCookie = new Cookie("remember_me", rememberToken);
                rememberCookie.setMaxAge(30 * 24 * 3600);  // 30 days - VERY vulnerable!
                rememberCookie.setHttpOnly(true);
                rememberCookie.setPath("/");
                // Missing: rememberCookie.setSecure(true);

                response.addCookie(rememberCookie);

                // Store token in database
                storeRememberToken(username, rememberToken);
            }

            response.getWriter().write("{\"status\": \"logged_in\"}");
        } else {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write("{\"error\": \"Invalid credentials\"}");
        }
    }

    private String generateSecureToken() {
        byte[] randomBytes = new byte[32];
        secureRandom.nextBytes(randomBytes);
        return Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes);
    }

    private boolean authenticateUser(String username, String password) {
        return true;
    }

    private void storeRememberToken(String username, String token) {
        // Database storage
    }
}

Why this is vulnerable:

  • Long-lived cookies especially dangerous
  • 30-day exposure window
  • No secure flag = persistent vulnerability
  • Enables long-term session hijacking
// VULNERABLE - Jakarta EE (Java EE) application with insecure cookies
package com.example.jakartaee;

import jakarta.servlet.http.*;
import jakarta.servlet.annotation.WebServlet;
import java.io.IOException;
import java.util.UUID;

@WebServlet("/jakarta-login")
public class JakartaLoginServlet extends HttpServlet {

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

        String username = request.getParameter("username");
        String password = request.getParameter("password");

        if (authenticateUser(username, password)) {
            String token = UUID.randomUUID().toString();

            // VULNERABLE - Jakarta Cookie without secure flag
            Cookie authCookie = new Cookie("auth_token", token);
            authCookie.setMaxAge(3600);
            authCookie.setHttpOnly(true);
            authCookie.setPath("/");
            // Missing: authCookie.setSecure(true);

            response.addCookie(authCookie);
            response.setContentType("application/json");
            response.getWriter().write("{\"status\": \"logged_in\"}");
        } else {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setContentType("application/json");
            response.getWriter().write("{\"error\": \"Invalid credentials\"}");
        }
    }

    private boolean authenticateUser(String username, String password) {
        return true;
    }
}

Why this is vulnerable:

  • Jakarta EE cookies missing secure flag
  • Modern Java EE still requires explicit security
  • Production deployment risk
  • Session hijacking possible
// VULNERABLE - Spring Session with custom cookie configuration
package com.example.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer;

@Configuration
public class VulnerableSessionConfig {

    @Bean
    public CookieSerializer cookieSerializer() {
        DefaultCookieSerializer serializer = new DefaultCookieSerializer();
        serializer.setCookieName("SESSIONID");
        serializer.setCookiePath("/");
        serializer.setCookieMaxAge(1800);  // 30 minutes
        serializer.setUseHttpOnlyCookie(true);
        serializer.setSameSite("Strict");
        // VULNERABLE - Not setting secure flag
        // serializer.setUseSecureCookie(true);  // MISSING!

        return serializer;
    }
}

Why this is vulnerable:

  • Spring Session cookies not secure
  • Custom serializer misconfigured
  • Production deployment vulnerable
  • Framework override error
// VULNERABLE - Micronaut application with insecure cookies
package com.example.micronaut;

import io.micronaut.http.HttpResponse;
import io.micronaut.http.annotation.*;
import io.micronaut.http.cookie.Cookie;
import java.util.UUID;

@Controller("/auth")
public class MicronautAuthController {

    @Post("/login")
    public HttpResponse<?> login(
            @Body LoginRequest request) {

        if (authenticateUser(request.getUsername(), request.getPassword())) {
            String sessionToken = UUID.randomUUID().toString();

            // VULNERABLE - Cookie without secure flag
            Cookie cookie = Cookie.of("session_id", sessionToken)
                .maxAge(3600)
                .httpOnly(true)
                .path("/");
                // Missing: .secure(true)

            return HttpResponse.ok()
                .body("{\"status\": \"logged_in\"}")
                .cookie(cookie);
        }

        return HttpResponse.unauthorized()
            .body("{\"error\": \"Invalid credentials\"}");
    }

    private boolean authenticateUser(String username, String password) {
        return true;
    }

    static class LoginRequest {
        private String username;
        private String password;

        public String getUsername() { return username; }
        public void setUsername(String username) { this.username = username; }
        public String getPassword() { return password; }
        public void setPassword(String password) { this.password = password; }
    }
}

Why this is vulnerable:

  • Micronaut cookies missing secure flag
  • Modern framework still requires explicit security
  • Production deployment risk
  • Builder pattern incomplete

Secure Patterns

SecureLoginServlet.java
// SECURE - Servlet cookie with proper security flags
import javax.servlet.http.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
import java.security.SecureRandom;
import java.util.Base64;

@WebServlet("/secure-login")
public class SecureLoginServlet extends HttpServlet {

    private static final SecureRandom secureRandom = new SecureRandom();

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

        String username = request.getParameter("username");
        String password = request.getParameter("password");

        if (authenticateUser(username, password)) {
            String sessionToken = generateSecureToken();

            // SECURE - Cookie with all critical security flags
            Cookie sessionCookie = new Cookie("JSESSIONID", sessionToken);
            sessionCookie.setSecure(true);      // HTTPS only
            sessionCookie.setHttpOnly(true);    // Not accessible via JavaScript
            sessionCookie.setPath("/");
            sessionCookie.setMaxAge(3600);      // 1 hour
            // Note: SameSite requires Servlet 6.0+ or manual header

            // For Servlet < 6.0, set SameSite manually in the Set-Cookie header
            String cookieHeader = String.format(
                "%s=%s; Path=%s; Max-Age=%d; Secure; HttpOnly; SameSite=Strict",
                sessionCookie.getName(),
                sessionCookie.getValue(),
                sessionCookie.getPath(),
                sessionCookie.getMaxAge()
            );
            response.addHeader("Set-Cookie", cookieHeader);

            response.setContentType("application/json");
            response.getWriter().write("{\"status\": \"logged_in\"}");
        } else {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setContentType("application/json");
            response.getWriter().write("{\"error\": \"Invalid credentials\"}");
        }
    }

    private String generateSecureToken() {
        byte[] randomBytes = new byte[32];
        secureRandom.nextBytes(randomBytes);
        return Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes);
    }

    private boolean authenticateUser(String username, String password) {
        // Secure authentication logic (bcrypt, etc.)
        return true;
    }
}

Why this works:

  • Secure + HttpOnly restrict cookie transport and script access.
  • SameSite=Strict blocks cross-site sending.
  • Strong tokens and short lifetimes reduce exposure.
application.properties
# SECURE configuration
server.port=8443
server.ssl.enabled=true
server.ssl.key-store=classpath:keystore.p12
server.ssl.key-store-password=${SSL_KEYSTORE_PASSWORD}
server.ssl.key-store-type=PKCS12

# SECURE - Session cookie security
server.servlet.session.cookie.secure=true
server.servlet.session.cookie.http-only=true
server.servlet.session.cookie.same-site=strict
server.servlet.session.timeout=30m
SecurityConfig.java
package com.example.security;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

@Configuration
@EnableWebSecurity
public class SecureSecurityConfig {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .requiresChannel(channel -> channel
                .anyRequest().requiresSecure()  // Force HTTPS
            )
            .authorizeHttpRequests(auth -> auth
                .requestMatchers("/public/**").permitAll()
                .anyRequest().authenticated()
            )
            .formLogin(form -> form
                .loginPage("/login")
                .permitAll()
            )
            .sessionManagement(session -> session
                .sessionFixation().newSession()
                .maximumSessions(1)
            );

        return http.build();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(12);
    }
}
LoginController.java
package com.example.controller;

import org.springframework.web.bind.annotation.*;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import java.security.SecureRandom;
import java.util.Base64;

@RestController
@RequestMapping("/api")
public class SecureLoginController {

    private static final SecureRandom secureRandom = new SecureRandom();

    @PostMapping("/login")
    public LoginResponse login(
            @RequestParam String username,
            @RequestParam String password,
            HttpServletResponse response) {

        if (authenticateUser(username, password)) {
            String token = generateSecureToken();

            // SECURE - Custom cookie with all security flags
            Cookie authCookie = new Cookie("auth_token", token);
            authCookie.setSecure(true);      // HTTPS only
            authCookie.setHttpOnly(true);    // Not accessible via JavaScript
            authCookie.setPath("/");
            authCookie.setMaxAge(3600);      // 1 hour

            // Add SameSite manually (Spring Boot 2.6+ has built-in support)
            response.addHeader("Set-Cookie",
                String.format("%s=%s; Path=/; Max-Age=%d; Secure; HttpOnly; SameSite=Strict",
                    authCookie.getName(), authCookie.getValue(), authCookie.getMaxAge()));

            return new LoginResponse("logged_in", username);
        }

        throw new RuntimeException("Invalid credentials");
    }

    private String generateSecureToken() {
        byte[] randomBytes = new byte[32];
        secureRandom.nextBytes(randomBytes);
        return Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes);
    }

    private boolean authenticateUser(String username, String password) {
        // Secure authentication (BCrypt, etc.)
        return true;
    }

    static class LoginResponse {
        public String status;
        public String username;

        public LoginResponse(String status, String username) {
            this.status = status;
            this.username = username;
        }
    }
}

Why this works:

  • App-wide session cookie flags + HTTPS enforcement reduce misconfig risk.
  • Session fixation protection limits reuse of old identifiers.
  • Custom cookies add Secure/HttpOnly/SameSite with strong tokens.
// SECURE - JAX-RS REST API with secure cookies
package com.example.api;

import javax.ws.rs.*;
import javax.ws.rs.core.*;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.Date;

@Path("/auth")
public class SecureAuthResource {

    private static final SecureRandom secureRandom = new SecureRandom();

    @POST
    @Path("/login")
    @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
    @Produces(MediaType.APPLICATION_JSON)
    public Response login(
            @FormParam("username") String username,
            @FormParam("password") String password) {

        if (authenticateUser(username, password)) {
            String sessionToken = generateSecureToken();

            // SECURE - NewCookie with all security flags (JAX-RS 2.0+)
            NewCookie cookie = new NewCookie.Builder("session_id")
                .value(sessionToken)
                .path("/")
                .maxAge(3600)
                .secure(true)      // HTTPS only
                .httpOnly(true)    // Not accessible via JavaScript
                .sameSite(NewCookie.SameSite.STRICT)  // JAX-RS 3.0+
                .build();

            return Response.ok()
                .entity("{\"status\": \"logged_in\"}")
                .cookie(cookie)
                .build();
        }

        return Response.status(Response.Status.UNAUTHORIZED)
            .entity("{\"error\": \"Invalid credentials\"}")
            .build();
    }

    @POST
    @Path("/logout")
    public Response logout() {
        // SECURE - Delete cookie with same security settings
        NewCookie deleteCookie = new NewCookie.Builder("session_id")
            .value("")
            .path("/")
            .maxAge(0)
            .secure(true)
            .httpOnly(true)
            .build();

        return Response.ok()
            .entity("{\"status\": \"logged_out\"}")
            .cookie(deleteCookie)
            .build();
    }

    private String generateSecureToken() {
        byte[] randomBytes = new byte[32];
        secureRandom.nextBytes(randomBytes);
        return Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes);
    }

    private boolean authenticateUser(String username, String password) {
        return true;
    }
}

Why this works:

  • Builder enforces Secure/HttpOnly/SameSite flags at creation time.
  • Logout deletes cookies with matching attributes.
  • Strong tokens and expirations reduce exposure.

JSP/Servlet Web.xml Configuration

web.xml
<!-- SECURE configuration -->
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
                             http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
         version="4.0">

    <!-- SECURE: Session configuration -->
    <session-config>
        <session-timeout>30</session-timeout>
        <cookie-config>
            <secure>true</secure>           <!-- HTTPS only -->
            <http-only>true</http-only>     <!-- XSS protection -->
            <same-site>Strict</same-site>   <!-- CSRF protection -->
        </cookie-config>
        <tracking-mode>COOKIE</tracking-mode>
    </session-config>

    <!-- SECURE: Security constraints -->
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Protected Area</web-resource-name>
            <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <user-data-constraint>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>
    </security-constraint>

</web-app>
SecureSessionServlet.java
package com.example.servlet;

import javax.servlet.http.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;

@WebServlet("/secure-session-login")
public class SecureSessionServlet extends HttpServlet {

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

        String username = request.getParameter("username");
        String password = request.getParameter("password");

        if (authenticateUser(username, password)) {
            // SECURE - Session cookie inherits web.xml config (secure flag enabled)
            HttpSession session = request.getSession(true);
            session.setAttribute("username", username);
            session.setAttribute("authenticated", true);
            session.setMaxInactiveInterval(1800);  // 30 minutes

            // Prevent session fixation
            String oldSessionId = session.getId();
            request.changeSessionId();

            response.setContentType("application/json");
            response.getWriter().write("{\"status\": \"logged_in\"}");
        } else {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setContentType("application/json");
            response.getWriter().write("{\"error\": \"Invalid credentials\"}");
        }
    }

    private boolean authenticateUser(String username, String password) {
        return true;
    }
}

Why this works:

  • Centralized web.xml flags secure all container-managed cookies.
  • Transport guarantee forces HTTPS at the container level.
  • Session fixation protection rotates IDs after login.

Secure Remember-Me Implementation

// SECURE - Remember-me with proper security
package com.example.auth;

import javax.servlet.http.*;
import javax.servlet.annotation.WebServlet;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.SecureRandom;
import java.util.Base64;

@WebServlet("/secure-remember-login")
public class SecureRememberMeServlet extends HttpServlet {

    private static final SecureRandom secureRandom = new SecureRandom();

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

        String username = request.getParameter("username");
        String password = request.getParameter("password");
        boolean rememberMe = "true".equals(request.getParameter("remember_me"));

        if (authenticateUser(username, password)) {
            String sessionToken = generateSecureToken();

            // SECURE - Session cookie with all flags
            Cookie sessionCookie = createSecureCookie("session_id", sessionToken, 3600);
            addCookieWithSameSite(response, sessionCookie);

            if (rememberMe) {
                String rememberToken = generateSecureToken();

                // Store hashed token in database
                String tokenHash = hashToken(rememberToken);
                storeRememberToken(username, tokenHash);

                // SECURE - Remember-me cookie with all flags
                Cookie rememberCookie = createSecureCookie(
                    "remember_me",
                    rememberToken,
                    30 * 24 * 3600  // 30 days
                );
                addCookieWithSameSite(response, rememberCookie);
            }

            response.setContentType("application/json");
            response.getWriter().write("{\"status\": \"logged_in\"}");
        } else {
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.setContentType("application/json");
            response.getWriter().write("{\"error\": \"Invalid credentials\"}");
        }
    }

    private Cookie createSecureCookie(String name, String value, int maxAge) {
        Cookie cookie = new Cookie(name, value);
        cookie.setSecure(true);      // HTTPS only
        cookie.setHttpOnly(true);    // Not accessible via JavaScript
        cookie.setPath("/");
        cookie.setMaxAge(maxAge);
        return cookie;
    }

    private void addCookieWithSameSite(HttpServletResponse response, Cookie cookie) {
        String header = String.format(
            "%s=%s; Path=%s; Max-Age=%d; Secure; HttpOnly; SameSite=Strict",
            cookie.getName(),
            cookie.getValue(),
            cookie.getPath(),
            cookie.getMaxAge()
        );
        response.addHeader("Set-Cookie", header);
    }

    private String generateSecureToken() {
        byte[] randomBytes = new byte[32];
        secureRandom.nextBytes(randomBytes);
        return Base64.getUrlEncoder().withoutPadding().encodeToString(randomBytes);
    }

    private String hashToken(String token) {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] hash = digest.digest(token.getBytes());
            return Base64.getEncoder().encodeToString(hash);
        } catch (Exception e) {
            throw new RuntimeException("Hashing failed", e);
        }
    }

    private boolean authenticateUser(String username, String password) {
        return true;
    }

    private void storeRememberToken(String username, String tokenHash) {
        // Database storage (store hash, not plaintext)
    }
}

Why this works:

  • Secure/HttpOnly/SameSite are enforced consistently for long-lived cookies.
  • Token hashing limits impact of database compromise.
  • Short session lifetimes reduce exposure.

Spring Session With Secure Configuration

// SECURE - Spring Session with proper cookie configuration
package com.example.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.session.web.http.CookieSerializer;
import org.springframework.session.web.http.DefaultCookieSerializer;

@Configuration
public class SecureSessionConfig {

    @Bean
    public CookieSerializer cookieSerializer() {
        DefaultCookieSerializer serializer = new DefaultCookieSerializer();

        serializer.setCookieName("SESSIONID");
        serializer.setCookiePath("/");
        serializer.setCookieMaxAge(1800);  // 30 minutes

        // SECURE - All security flags enabled
        serializer.setUseSecureCookie(true);     // HTTPS only
        serializer.setUseHttpOnlyCookie(true);   // XSS protection
        serializer.setSameSite("Strict");        // CSRF protection

        return serializer;
    }
}

Why this works:

  • Secure/HttpOnly/SameSite flags are enforced at the serializer level.
  • HTTPS-only cookies protect session IDs in transit.
  • Reasonable expiration limits exposure.

Verification

After implementing the recommended secure patterns, verify the fix through multiple approaches:

  • Manual testing: Submit malicious payloads relevant to this vulnerability and confirm they're handled safely without executing unintended operations
  • Code review: Confirm all instances use the secure pattern (parameterized queries, safe APIs, proper encoding) with no string concatenation or unsafe operations
  • Static analysis: Use security scanners to verify no new vulnerabilities exist and the original finding is resolved
  • Regression testing: Ensure legitimate user inputs and application workflows continue to function correctly
  • Edge case validation: Test with special characters, boundary conditions, and unusual inputs to verify proper handling
  • Framework verification: If using a framework or library, confirm the recommended APIs are used correctly according to documentation
  • Authentication/session testing: Verify security controls remain effective and cannot be bypassed (if applicable to the vulnerability type)
  • Rescan: Run the security scanner again to confirm the finding is resolved and no new issues were introduced

Additional Resources