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
secureattribute - 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.xmlor 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
Servlet Cookie Without Secure Flag
// 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
// 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();
}
}
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
JAX-RS Cookie Without Security
// 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:
NewCookiesecure parameter set tofalse- Cookie sent over HTTP
- REST API authentication compromised
- Token interception possible
JSP Session Cookie Misconfiguration
<!-- 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>
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.xmlmissing<secure>true</secure>- Session cookies transmitted over HTTP
- Container-managed sessions vulnerable
- Configuration error
Remember-Me Cookie Without Secure Flag
// 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
Jakarta EE Cookie Without Security
// 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
Spring Session Cookie Misconfiguration
// 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
Micronaut Cookie Without Security
// 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
Servlet Cookie With All Security Flags
// 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.
Spring Boot With Secure Cookie Configuration
# 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
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);
}
}
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.
JAX-RS Cookie With Security
// 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
<!-- 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>
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