skip to content

What do the `Secure` and `HttpOnly` attributes on an HTTP Set-Cookie header do, and which attack does each one address?

level: juniorimportance: must knowfreq 70%

answer

  1. Secure = HTTPS only on the wire
  2. HttpOnly = invisible to document.cookie
  3. HttpOnly limits XSS to session-riding, not theft
  4. cookie scope ignores scheme — hence Secure
  5. neither is echoed back; that is what __Host- is for

basics

~20 s

Secure tells the browser to send the cookie only over HTTPS, protecting it from network eavesdroppers. HttpOnly hides it from JavaScript's document.cookie, so cross-site scripting cannot read and exfiltrate it. Session cookies should carry both.

solid answer

~60 s

**`Secure`**: the browser will not attach the cookie to plain `http://` requests. Without it, one accidental HTTP request — a hardcoded link, a captive portal, a downgrade attempt — sends the session cookie in cleartext to anyone on the path. Localhost is treated as secure so development still works. **`HttpOnly`**: the cookie is excluded from `document.cookie` and from script-visible response headers. If an attacker achieves XSS on your origin, they cannot simply read the session cookie and post it to their server. It is not a cure for XSS — the attacker's script still runs on your origin and can make authenticated requests as the user, since the browser attaches the cookie automatically — but it turns "steal the session forever" into "act only while my script runs on this page". Both are enforced by the browser and neither is echoed back in the `Cookie` header, so the server cannot verify them; that is what the `__Host-` name prefix is for. Set both on any authentication cookie, together with an appropriate `SameSite`.

code

http · 2 lines
http
Set-Cookie: __Host-sid=9f2c...; Path=/; Secure; HttpOnly; SameSite=Lax
Set-Cookie: csrf=7ab1...; Path=/; Secure; SameSite=Lax

go deeper

for a junior

State both crisply — Secure = HTTPS only, HttpOnly = not readable by JavaScript — and name the attack each addresses.

for a middle

Add that cookie scope ignores scheme (so HTTPS-only sites still need Secure) and that HttpOnly limits XSS to session riding rather than credential theft.

for a senior

Discuss the residual XSS capability, why localStorage tokens forfeit the protection, and enforcing attributes centrally with tests since misconfiguration is silent.

for a principal

Position them as one layer in a credential strategy — opaque short-lived sessions, CSP, prefixes, rotation — and decide the org-wide default for how credentials are stored and handed to front ends.

## Secure — transport confidentiality `Set-Cookie: sid=abc; Secure` instructs the browser to include the cookie only on requests over a secure transport: HTTPS, and by exception `http://localhost` and `127.0.0.1`, which browsers treat as potentially-trustworthy so local development works. Why it matters even on an all-HTTPS site: cookie scope ignores the URL scheme. Without `Secure`, a cookie set over HTTPS is happily sent over HTTP to the same host. An attacker on the network only needs to make the browser emit **one** plaintext request — an `http://` image in a forum post, a link in an email, a hijacked DNS answer on a coffee-shop network, a captive-portal redirect — and the session cookie crosses the wire in the clear. HSTS reduces the window by making the browser rewrite `http://` to `https://`, but HSTS has a first-visit gap and applies per host; `Secure` is unconditional and free. Modern browsers additionally require `Secure` for cookies with `SameSite=None`, and refuse to let an insecure origin overwrite a `Secure` cookie — closing the older "cookie written over HTTP" hole. ## HttpOnly — script confidentiality `Set-Cookie: sid=abc; HttpOnly` removes the cookie from the JavaScript view of the jar. `document.cookie` will not list it, scripts cannot overwrite it, and it does not appear in headers exposed to `fetch`/`XMLHttpRequest` responses. The threat is **cross-site scripting**: attacker-controlled script running on your origin. Without `HttpOnly` the classic payload is one line — read `document.cookie`, send it to the attacker's server — and the attacker then replays the session from their own machine, at leisure, from any IP, with no further access to the victim's browser. With `HttpOnly` that path closes. What remains is important to state honestly, because interviewers probe it: the attacker's script still runs with your origin's privileges, and the browser attaches the cookie to requests the script makes. So they can call your APIs as the user, read the responses, change the email address, create an API token. `HttpOnly` does not stop *acting as the user*; it stops *taking the credential away*. That distinction — confining the compromise to the lifetime of the injected script rather than handing over a portable credential — is the whole value, and it is real, but it is not a substitute for output encoding, a Content Security Policy, and fixing the injection. A corollary: any design where JavaScript must read the credential (storing a token in `localStorage`, or in a non-HttpOnly cookie so an SPA can attach it as a header) forfeits this protection by construction. That is the core argument for keeping session credentials in `HttpOnly` cookies rather than in web storage. ## What neither attribute does - Neither encrypts the cookie value. The value is plaintext to the server, to anyone with the device, and to browser extensions with the right permissions. If the value is sensitive beyond being an opaque identifier, it should be signed and/or encrypted server-side. - Neither prevents cross-site request forgery. CSRF is about a *cross-site request* triggering an authenticated action, and the browser attaches the cookie regardless of `Secure` or `HttpOnly`. `SameSite` plus CSRF tokens address that. - Neither is visible to the server on subsequent requests: the `Cookie` header carries names and values only. A server cannot check "was this cookie HttpOnly?". If you need that guarantee, use the `__Host-` name prefix, which browsers enforce at write time and which is visible in the name. ## Practical rule For an authentication or session cookie, the baseline is: `Set-Cookie: __Host-sid=<opaque>; Secure; HttpOnly; SameSite=Lax; Path=/` Omit `HttpOnly` only for cookies that genuinely must be read by scripts — for example a double-submit CSRF token or a non-sensitive UI preference — and keep no credential value in them. Enforce the attributes centrally in the framework's cookie-writing helper rather than at each call site, and assert them in tests, because a missing `Secure` or `HttpOnly` is invisible in normal use and only surfaces in an incident.

  • If a site has XSS, does HttpOnly save it?
    No. The attacker's script runs on your origin, and the browser attaches the HttpOnly cookie to every request that script makes, so it can perform authenticated actions and read the responses. HttpOnly only prevents the credential itself from being exfiltrated and replayed elsewhere later, which limits the blast radius to the time the script is running.
  • Why does a site that is HTTPS-only still need the Secure attribute?
    Cookie scoping ignores the URL scheme, so a cookie without Secure is sent on any plain http:// request to the same host. A single accidental or attacker-induced HTTP request — an http image URL, a typed link, a captive portal — leaks the cookie in cleartext. HSTS narrows the window but has a first-visit gap, whereas Secure is unconditional.

Secure is sending the key only through a sealed tube. HttpOnly is letting the doorman hold the key: visitors can still ask him to open the door while they are there, but they cannot walk off with it.

saying these in an interview costs you the question

  • Claiming HttpOnly prevents XSS or makes an XSS harmless
  • Thinking Secure encrypts the cookie value rather than restricting the transport
  • Believing HttpOnly or Secure stop CSRF
  • Assuming an HTTPS-only site does not need Secure
  • Putting session tokens in localStorage and calling it equivalent to an HttpOnly cookie

context