Safety
HttpOnly vs Secure vs SameSite Cookies for Session OPSEC
May 10, 2024
HttpOnly vs Secure vs SameSite is not an either-or decision for session cookies. HttpOnly keeps the cookie out of document.cookie. Secure stops it from traveling on HTTP. SameSite limits when the browser attaches it to cross-site requests. Auth and session cookies on a public site should usually carry all three: Secure, HttpOnly, and SameSite=Lax or Strict. RoastMyOpsec grades session-like cookies on the landing Set-Cookie headers only — no login automation — so absence can be inconclusive if the cookie is issued later.
The practical difference
These flags solve different theft paths. Missing HttpOnly means any XSS on the page can read the session. Missing Secure means a cleartext hop can leak it. Missing or None SameSite means the cookie may ride along on cross-site GET/POST depending on browser defaults and your Chrome-era exceptions.
Marketing pixels and preference cookies are not the same as session cookies. Grade the cookies that look like sessions, auth, or JWTs first. Analytics cookies can stay less privileged; they should never be your login.
How to choose based on the cookie's job
Start with what the cookie authorizes. If it can change account state or prove login, it is a vault key and gets the hard flags. If it only stores a theme or a cart id without auth, the blast radius is smaller but Secure is still cheap on an HTTPS site.
| Cookie job | HttpOnly | Secure | SameSite | Takeaway |
|---|---|---|---|---|
| Session / auth | Required | Required | Lax or Strict | Treat as a credential. Never readable to JS. |
| CSRF token cookie | Often false (JS must read it) | Required | Strict or Lax with server Origin checks | Different pattern — do not copy session flags blindly |
| Preferences | Optional | Required on HTTPS sites | Lax is usually enough | Do not store secrets here |
| Third-party embed | Depends on vendor | Required | None requires Secure and a real cross-site need | Avoid None unless the product actually embeds cross-site |
When SameSite=Lax wins
Lax wins for most cookie-based web apps that need top-level GET navigations from email or search to land the user logged in. It still blocks many cross-site POSTs from attaching the cookie.
Strict wins when the app is a high-value console and you would rather make users click through your own origin than accept inbound cross-site GETs with credentials.
When SameSite=None is a trap
None is for genuine cross-site credentialed embeds. It requires Secure. Using None 'so OAuth works' without understanding the callback is a common way to reopen CSRF-shaped problems.
If you do not have a third-party iframe that must send your session cookie, you do not need None.
What a public scan can and cannot see
RoastMyOpsec parses Set-Cookie on the URL you submit. If the session cookie is only issued after login, the free cookie check may be inconclusive. That is honest grading, not a pass.
Fix flags in the app or at the edge, then hit a URL that actually sets the cookie — or confirm in your browser's Application panel on an account you own.
Common mistakes
The first mistake is putting session tokens in document.cookie so frontend JS can 'just read them.'
The second mistake is Secure on production and missing it on the staging host that still uses real accounts.
The third mistake is copying a marketing-site cookie policy onto the app domain that holds sessions.
Free audit the URL you own
RoastMyOpsec is a defensive public-surface roast: headers, cookies, sensitive paths, and more — no exploit payloads. Start with the free audit, then open the vault if the blurred findings look expensive.
Free audit nowFAQ
- Do I need HttpOnly, Secure, and SameSite on every cookie?
- You need all three on session and auth cookies. Other cookies should still be Secure on HTTPS sites. HttpOnly depends on whether JavaScript must read the value.
- Is SameSite=Lax or Strict better?
- Lax is the usual default for sites that receive logged-in traffic from external links. Strict is stronger for consoles where inbound cross-site GETs should not carry the session.
- Why did an OPSEC scan not see my auth cookie?
- Public scans only see Set-Cookie on the requested URL. Cookies issued after login are often invisible without authenticated testing. Check the response that actually establishes the session.