Cookie Security: HttpOnly, Secure, and SameSite Flags

Cookie Security: HttpOnly, Secure, and SameSite Flags

Cookie security flags – HttpOnly, Secure, and SameSite – are among the most straightforward protections a web application can implement, yet misconfigured or missing flags remain one of the most common findings in any web application security audit. This article covers what each flag does, where developers go wrong, and how to verify your cookies are actually protected.

Session hijacking has not disappeared as an attack class. It has evolved. Attackers who gain access to a valid session cookie can impersonate any user, including administrators, without ever needing a password. The three flags discussed here are your first line of defence against the most common paths to that outcome.

What Cookie Security Flags Actually Control

Cookies carry sensitive data – session tokens, authentication state, preferences tied to accounts. Without explicit flags, the browser treats cookies as freely accessible: readable by JavaScript, transmittable over plain HTTP, and shareable across requests to third-party origins.

Each flag narrows that default permissiveness in a specific direction. Understanding what each flag does mechanically makes it much easier to apply them correctly and to spot gaps during a security review.

HttpOnly tells the browser to block JavaScript from reading the cookie entirely. document.cookie will not return it. This directly removes one of the most dangerous outcomes of a cross-site scripting (XSS) attack – an attacker injecting a script to steal session tokens. The cookie still travels with every HTTP request; it just cannot be accessed programmatically from the page.

Secure instructs the browser to only transmit the cookie over HTTPS connections. On plain HTTP, the cookie is simply not sent. This matters in mixed network environments, coffee shop Wi-Fi scenarios, or during misconfigured redirects where a request briefly travels over HTTP before being upgraded.

SameSite controls whether a cookie is sent along with cross-site requests. It has three values: Strict, Lax, and None. Strict means the cookie is never sent with any cross-origin request. Lax (now the browser default in most cases) allows cookies on top-level navigations like clicking a link, but blocks them on subresource requests. None requires the Secure flag to be set simultaneously and allows cross-site cookies – used for third-party embeds and federated authentication flows.

Where Development Teams Consistently Get This Wrong

The most common mistake is not missing flags on one or two cookies – it is missing them systematically across every cookie in the application because the session framework was set up once, years ago, and no one reviewed the defaults.

Another frequent issue involves the SameSite flag specifically. Developers correctly set Strict on authentication cookies, then discover that OAuth callbacks or cross-domain redirects from payment providers break authentication flow entirely. The typical rushed fix is to drop SameSite to None without pausing to evaluate whether Lax would be sufficient. None without Secure then exposes the cookie to network interception.

A subtler problem appears with cookie scope. Even when the flags are set correctly, cookies scoped to an overly broad domain (for example, .example.com instead of app.example.com) can be accessible to subdomains that may be less hardened or even under different ownership. This is a pattern that often intersects with subdomain-level security risks.

It is also worth comparing cookies to browser storage alternatives. localStorage is always accessible to JavaScript on the same origin, with no equivalent of HttpOnly protection. Developers who migrate session tokens to localStorage to work around cookie complexity have removed a significant security control, not simplified the architecture.

Myth: HTTPS Alone Makes Cookies Safe

A persistent misconception is that once a site runs on HTTPS, cookie security is handled. HTTPS encrypts the transport layer, which protects cookies in transit from network sniffing. But it does nothing to prevent JavaScript-based theft (HttpOnly addresses that), cross-site request forgery via ambient credentials (SameSite addresses that), or cookies being silently downgraded and transmitted during an HTTP request triggered before a redirect completes.

Transport security and cookie-level security are separate layers. Both need to be configured deliberately. HTTPS is necessary but not sufficient.

Setting the Flags: A Practical Reference

The exact implementation varies by platform, but the logic is consistent.

In an HTTP response header, a fully hardened session cookie looks like this:

Set-Cookie: session=abc123; HttpOnly; Secure; SameSite=Lax; Path=/; Max-Age=3600

For most authentication cookies, SameSite=Lax is the pragmatic choice – it blocks the most common CSRF vectors while keeping same-site navigation functional. Reserve Strict for security-critical cookies like CSRF tokens where you can tolerate stricter behaviour.

In frameworks: Express.js exposes these through the cookie options object; Django’s SESSION_COOKIE_SECURE, SESSION_COOKIE_HTTPONLY, and SESSION_COOKIE_SAMESITE settings map directly; PHP’s session_set_cookie_params() accepts all three. Check your framework documentation and verify what the defaults actually are – do not assume they are secure by default.

One practical step that often gets skipped: after deploying changes, inspect the Set-Cookie headers in browser DevTools under the Application tab. Confirm each flag appears. A deployment that failed silently, or a load balancer stripping headers, will be immediately visible here.

Cookie security configuration overlaps with the broader topic of browser security headers – both operate at the HTTP response level and both are commonly audited together in a web security review.

Verifying Your Cookies Are Properly Configured

Manual inspection covers a handful of cookies during development, but production applications often set cookies across multiple endpoints, redirect flows, and third-party integrations. Relying on spot-checks misses gaps.

Automated website security scanning identifies cookies missing required flags across the full application surface – not just the login page, but password reset flows, API responses, and third-party callback handlers. Reviewing findings in a structured report makes it straightforward to prioritise which gaps carry actual risk versus which are low-sensitivity cookies where relaxed flags are acceptable.

Frequently Asked Questions

Does setting HttpOnly break any legitimate use case?
Rarely. HttpOnly prevents JavaScript from reading the cookie, which is the right behaviour for session tokens and authentication credentials. If application code relies on reading a session cookie via JavaScript, that is an architectural issue worth resolving – the fix is to use a separate, non-sensitive cookie or an API call for the data that JavaScript needs.

Can SameSite=Strict cause authentication problems with external logins?
Yes, and this is a well-known trade-off. If a user clicks an email link or arrives from an OAuth provider, SameSite=Strict will suppress the session cookie on that initial cross-origin navigation, logging the user out or forcing re-authentication. SameSite=Lax handles this more gracefully for most applications. Reserve Strict for supplementary security cookies, not the primary session cookie.

Do modern browsers enforce these flags automatically?
Browsers have moved toward treating cookies without a SameSite flag as Lax by default in recent versions of Chrome and Firefox. But Secure and HttpOnly still require explicit server-side configuration – browsers do not add them automatically. Never rely on browser defaults for security-critical cookies.

Summary

HttpOnly, Secure, and SameSite are not optional hardening steps – they are baseline controls for any web application handling authenticated sessions. The flags are individually simple to set and collectively powerful: HttpOnly removes XSS-based token theft, Secure prevents transmission over unencrypted channels, and SameSite eliminates the ambient credential exposure that enables CSRF attacks.

The practical risk is not that teams do not know about these flags. It is that they are easy to overlook during initial setup, easy to misconfigure under pressure, and easy to forget when new endpoints or cookie types are added over time. Regular, automated security audits – especially ones that test cookie configurations across the full application surface – are the reliable way to catch gaps before attackers do.