KAHIBARO
Discord Login Register

15.13. Secure Cookies

Why Cookie Security Matters

Cookies are tiny pieces of data that browsers store and send with every request to a website. They are often used to keep users logged in, remember preferences, or track sessions.

From a backend perspective, cookies are high‑value targets. If an attacker can:

So “secure cookies” is really about how you store, protect, and validate cookie data so that even if something goes wrong, attackers gain as little as possible.

Secure cookies are primarily about:

  1. Limiting where and when cookies are sent.
  2. Making cookie contents hard or impossible to tamper with.
  3. Avoiding storage of sensitive secrets directly in cookies.

In this chapter you will see the main flags, patterns, and anti‑patterns that make cookies safe in a real backend application.


Cookie Basics Recap

A cookie is a name=value pair with optional attributes. The server sets a cookie using the Set-Cookie header in an HTTP response, for example:

http
Set-Cookie: session_id=abc123; Path=/; HttpOnly; Secure; SameSite=Lax

On subsequent requests to the same site, the browser automatically sends:

http
Cookie: session_id=abc123

Cookies are stored in the browser, not on the server. On the backend, you typically see only:

You do not control how the browser stores them, but you control what to set and how to validate what comes back.


Sensitive Data and Cookies

What is “sensitive” in a cookie?

Examples of sensitive data that should not be easily exposed:

You will often still store some of these indirectly in cookies, but you must protect them properly.

Bad ideas: what not to store in plaintext cookies

Avoid storing:

If an attacker can run JavaScript on your page (XSS), any readable cookie becomes visible to them. If you do not properly restrict cookie sending, some cookies may also be sent in cross‑site requests.

Rule: Never store passwords or raw secrets in cookies, especially not in plaintext.

Instead, store random identifiers that are meaningful only on the server side, or use strongly protected tokens with correct flags.


Cookie Attributes and Security Flags

Several cookie attributes directly affect security. They are part of the Set-Cookie header.

Common attributes:

AttributePurpose
DomainWhich domains can receive the cookie
PathWhich paths on the domain can receive it
ExpiresAbsolute expiration date
Max-AgeLifetime in seconds
SecureOnly send over HTTPS
HttpOnlyInaccessible to JavaScript
SameSiteRestrict cross-site sending (CSRF related)

You will use most of these together to get a secure cookie.


HttpOnly Flag

What HttpOnly does

HttpOnly tells the browser:

Do not make this cookie available to JavaScript (for example document.cookie).

The cookie is still sent automatically with HTTP requests, but any script running in the page cannot read or modify it.

Example:

http
Set-Cookie: session_id=abc123; Path=/; HttpOnly

With this cookie, code like:

js
console.log(document.cookie);

will not show session_id in most modern browsers.

This is critical to limit the damage of Cross‑Site Scripting (XSS). If an attacker injects JavaScript into your site, they can often steal any non‑HttpOnly cookie. They cannot directly read a properly set HttpOnly cookie.

Rule: All cookies that relate to authentication or sessions must be set with HttpOnly.

What HttpOnly does not protect against

HttpOnly does not:

So you still need complementary protections, such as SameSite, CSRF tokens, and HTTPS.


Secure Flag

What Secure does

Secure tells the browser:

Send this cookie only over HTTPS connections.

Example:

http
Set-Cookie: session_id=abc123; Path=/; HttpOnly; Secure

If someone accesses http://example.com, the browser will not include the cookie. Only https://example.com will receive it.

This reduces the risk that cookies leak over unencrypted connections. Without Secure, if you ever serve on plain HTTP or if traffic is intercepted, the cookie could be read in transit.

Rule: Any authentication or session cookie must be set with Secure and only used over HTTPS.

Local development considerations

In local development you might use http://localhost:8000. With Secure cookies:

Never ship to production with session cookies that lack Secure.


SameSite Flag

SameSite is essential to limit cross‑site requests carrying your cookies. It controls when the browser includes a cookie with a request coming from another site.

Common values:

ValueBehavior summary
LaxSend cookie on top‑level navigations (such as clicking a link), but not on most cross‑site subrequests.
StrictDo not send cookie on any cross‑site request, including top‑level navigations.
NoneSend cookie on all cross‑site requests. Must be combined with Secure.

Example:

http
Set-Cookie: session_id=abc123; Path=/; HttpOnly; Secure; SameSite=Lax

Why SameSite helps CSRF

Cross‑Site Request Forgery (CSRF) exploits the fact that browsers automatically send cookies in requests, even when the user is on another site.

SameSite helps by not sending cookies in many cross‑site cases. For example:

This does not remove the need for CSRF tokens in all cases, but it is a powerful layer.

Rule: Use SameSite=Lax as a safe default for most authentication cookies. Use SameSite=None; Secure only when cross‑site usage is required.

Choosing the right SameSite value

Example for cross‑site API cookie:

http
Set-Cookie: session_id=abc123; Path=/; HttpOnly; Secure; SameSite=None

Domain and Path Restrictions

Domain attribute

Domain tells the browser which hostnames the cookie is valid for.

Examples:

Example header:

http
Set-Cookie: session_id=abc123; Path=/; Domain=example.com; HttpOnly; Secure; SameSite=Lax

Security implications:

Rule: Use the narrowest Domain you can. Do not share sensitive cookies across unnecessary subdomains.

Path attribute

Path limits cookies to specific URL paths.

Examples:

http
Set-Cookie: session_id=abc123; Path=/; ...

Cookie is sent for:

Another example:

http
Set-Cookie: admin_token=xyz; Path=/admin; ...

Cookie is sent for:

This can help limit where a cookie is visible and reduce attack surface.

Use case: You might want:

Expiration and Max-Age

Cookies can be:

Examples:

http
Set-Cookie: session_id=abc123; Path=/; HttpOnly; Secure; SameSite=Lax

This is a session cookie.

http
Set-Cookie: remember_me=xyz; Path=/; HttpOnly; Secure; Max-Age=2592000; SameSite=Lax

This lasts 30 days (2592000 seconds) unless the user clears cookies.

Security notes:

Rule: Sensitive cookies, especially for powerful admin accounts, should have limited lifetimes and be rotated regularly.


Session Cookies vs Token Cookies

Two common patterns for authentication:

  1. Session ID cookie
    • Cookie value is a random ID such as "abc123" or a 32‑byte base64 string.
    • Server stores session data in a database or in Redis keyed by this ID.
    • Cookie by itself has little information, server decides what it means.
  2. Token cookie
    • Cookie value is a self‑contained token, often a JWT.
    • Token contains user ID and claims, possibly signed.
    • Server validates signature, then trusts claims without looking up session.

Security tradeoffs:

For absolute beginners, a safe approach is:

Start with simple session ID cookies stored in a secure server‑side session store. Use HttpOnly, Secure, and SameSite=Lax as defaults.


Signed and Encrypted Cookies

Sometimes you want to store data in a cookie but prevent tampering. For example:

http
Set-Cookie: preferences={"theme":"dark"}; ...

A malicious user could change it to:

http
preferences={"is_admin":true}

If your backend trusts the cookie blindly, this is a vulnerability.

Two strategies:

Signed cookies (integrity)

You generate a cookie value that includes:

For example, the logical value might be:

json
{"user_id": 123, "role": "user", "sig": "a1b2c3..."}

Only the server can compute the correct signature because it knows the secret key.

On each request:

  1. Read cookie.
  2. Extract data and signature.
  3. Recompute signature from data using secret.
  4. Compare signatures.
    • If they match, data is trusted.
    • If not, discard or reject.

If an attacker changes the data, the signature fails to verify.

Encrypted cookies (confidentiality + integrity)

You encrypt the content with a strong algorithm (for example AES) using a secret key.

This protects both integrity and confidentiality. Even if someone reads the cookie, they cannot see what is inside.

In many modern frameworks, encrypted or signed cookies are built in. For example:

Rule: If you store anything security relevant in cookies, either:

  1. Use a random session ID referencing server data, or
  2. Use signed/encrypted cookies managed by a well tested framework.
    Never roll your own cryptography.

Preventing Session Hijacking

Session hijacking occurs when an attacker obtains a user’s session cookie and uses it.

Secure cookie practices help reduce this risk:

  1. Use HttpOnly to block simple XSS based theft.
  2. Use Secure to avoid sending cookies over plain HTTP.
  3. Use SameSite to limit CSRF and some cross‑site leaks.
  4. Rotate session IDs:
    • When a user logs in, issue a new session ID and invalidate the old one.
    • On privileged actions, consider “re‑authentication” or rotation.
  5. Short lifetimes for important sessions.
  6. Bind sessions to context:
    • Optionally associate sessions with properties such as IP address or User‑Agent, then check for changes.
    • Be careful, as this can affect users behind shared networks or using mobile networks.

Example pattern:

http
Set-Cookie: session_id=<random>; Path=/; HttpOnly; Secure; SameSite=Lax

If a session cookie is stolen but you rotate frequently, the attacker has a shorter window of opportunity.


Preventing Session Fixation

Session fixation is when an attacker sets or forces a session ID for the victim, then later uses it after the victim logs in.

Typical unsafe flow:

  1. Attacker gets a valid session ID A.
  2. Attacker tricks user into using a link that sets session_id=A in some way.
  3. User logs in while using session A.
  4. Attacker now uses session A and is authenticated as the user.

To prevent this:

Rule: Always generate a brand new session ID after a successful login (and after privilege changes).

Implementation idea:

Example:

http
Set-Cookie: session_id=new_random_id; Path=/; HttpOnly; Secure; SameSite=Lax

After this, any session ID the attacker forced earlier is no longer valid.


Cookies and CSRF Protection

Cookies and CSRF are closely related because:

You improve CSRF resistance by:

  1. Setting SameSite appropriately.
  2. Implementing CSRF tokens where needed.
  3. Avoiding unnecessary cookie usage for cross‑site APIs (for example, using bearer tokens instead).

Example: SameSite=Lax plus CSRF token

A “double submit cookie” pattern:

  1. Server sets a CSRF cookie:
http
Set-Cookie: csrf_token=xyz; Path=/; Secure; SameSite=Lax
  1. Frontend reads the csrf_token cookie (this one is not HttpOnly) and includes it in a custom header X-CSRF-Token on each request.
  2. Server:
    • Checks that the cookie value and the header value match.
    • If not, rejects the request.

Attackers from other sites typically cannot set the correct header and cannot read the cookie value due to cross origin restrictions.


Practical Examples and Patterns

Example: Secure login session cookie

Assume domain: app.example.com, HTTPS only.

On login:

http
HTTP/1.1 200 OK
Set-Cookie: session_id=RANDOM_32_BYTE; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=3600
Content-Type: application/json
{"message": "logged in"}

Backend:

This is simple and secure enough for many apps.

Example: Remember me cookie

You might want “remember me” that persists after 1 hour. Use a separate cookie:

http
Set-Cookie: remember_me=TOKEN; Path=/; HttpOnly; Secure; SameSite=Lax; Max-Age=2592000

Where TOKEN is a random identifier stored in your database, hashed:

FieldValue
token_hashhash(TOKEN)
user_id42
created_at2026-08-20
expires_at2026-09-19 (30 days later)

On new visits:

This way, even if someone dumps database, they do not see the raw token.


Common Mistakes with Cookies

Here are some patterns to avoid:


MistakeWhy it is dangerous
No HttpOnly on session cookiesXSS can steal session identifiers.
No Secure on session cookiesCookies may be intercepted over HTTP.
SameSite=None without real needIncreases CSRF risk unnecessarily.
Using Domain=.example.com for all cookiesAll subdomains share powerful cookies.
Storing passwords or secrets in plaintextExposure from XSS, logs, browser export, etc.
No session rotation on loginVulnerable to session fixation attacks.
Overly long Max-Age for powerful sessionsLonger window for attackers to use stolen cookies.
Implementing custom crypto incorrectlyHard to get right, often leads to broken security.

Summary

Secure cookie handling combines multiple techniques:

Cookies are not “just storage”. They are part of your authentication and security model. Treat every sensitive cookie like a key to the user’s account and protect it with all the tools available.

These principles apply regardless of programming language or framework, and you will use them repeatedly in real backend systems.

Views: 8

Comments

Please login to add a comment.

Don't have an account? Register now!