Rudra Analyzer

How to check cookie security: Secure, HttpOnly, SameSite and cookie prefixes

Session cookies are keys to your visitors' accounts. How each cookie attribute protects them, how to inspect your own cookies, and how to set them correctly.

Rudra Techno Team 7 min read

When someone logs in to your site, the server usually hands their browser a session cookie. From then on, whoever holds that cookie is that user. Cookie attributes decide when the browser sends it, over which connections, and whether scripts on the page can read it. Getting them right costs a line of configuration; getting them wrong can turn a small bug into an account takeover.

The attributes that matter

Secure

Secure tells the browser to send the cookie only over HTTPS. Without it, the cookie can travel over a plain HTTP request — for example when someone types your domain without https:// before the redirect happens — where anyone on the same network can read it. On an HTTPS site, every cookie should be Secure.

HttpOnly

HttpOnly hides the cookie from JavaScript (document.cookie). If an attacker manages to inject a script into your page, they can't simply read a session cookie and send it elsewhere. Use it on session and authentication cookies. Cookies your own front-end code must read, such as a CSRF token some frameworks expose to JavaScript on purpose, can't be HttpOnly — that's expected.

SameSite

SameSite controls whether the cookie is sent when a request comes from another site:

  • SameSite=Strict: only sent on requests that start on your own site. Safest, but a visitor following a link from an email to your site arrives looking logged out.
  • SameSite=Lax: sent on top-level navigations such as clicking a link, but not on cross-site form posts, images or frames. A good default for session cookies.
  • SameSite=None: sent in every cross-site context, needed for embedded widgets and some single sign-on flows. It must be combined with Secure, or browsers reject the cookie.

Chromium-based browsers treat a cookie without a SameSite attribute as Lax, but not every browser behaves the same way, so set it explicitly.

Domain and Path

Leave out Domain and the cookie is host-only: sent only to the exact host that set it. Setting Domain=example.com shares it with every subdomain, including forgotten ones on other hosting that might be less secure. Only widen the scope when you really need to share a login across subdomains.

Expires and Max-Age

Without Expires or Max-Age, a cookie is meant to last for the browser session, though browsers that restore sessions can keep it longer. For persistent logins, choose a lifetime that matches the risk, and make sure the server also expires sessions on its side.

Cookie prefixes: __Host- and __Secure-

Cookie name prefixes let the browser enforce rules for you. A cookie whose name starts with __Secure- is only accepted if it has the Secure attribute and was set over HTTPS. A cookie starting with __Host- is stricter: it must be Secure, set over HTTPS, have Path=/ and no Domain attribute. That locks it to one host, so a compromised or careless subdomain can't overwrite it.

For a session cookie that doesn't need sharing across subdomains, __Host- is the strongest option available: Set-Cookie: __Host-session=…; Secure; HttpOnly; SameSite=Lax; Path=/.

How to check your cookies

  1. In the browser. Open developer tools, go to Application (Chrome, Edge) or Storage (Firefox), then Cookies, and select your site. The table shows each cookie's Domain, Path, Expires, HttpOnly, Secure and SameSite columns.
  2. In the raw response. In the Network tab, click the document request and read the Set-Cookie response headers. This shows exactly what the server sent, including attributes the browser might have rejected.
  3. After logging in. Many sites set their important cookies only after sign-in or when a cart is created, so check again on those pages.
  4. With a checker. Rudra's free security checker reads the Set-Cookie headers on the page's own response and reports cookies without Secure on HTTPS, session-like cookies without HttpOnly, SameSite=None without Secure, cookies with no SameSite, and cookies scoped to a parent domain.

Two limits of the automated check are worth knowing. It judges whether a cookie is "session-like" from its name (names containing things like sess, sid, token or auth), so it reports those findings at medium confidence: confirm what the cookie actually holds. And it only sees cookies set by that one response — not cookies set later by JavaScript, by other pages, after login, or by third parties. Cookie values are never read or stored.

Check your cookie flags

Enter a page and Rudra reports the Secure, HttpOnly and SameSite flags on the cookies it sets, by name only, alongside your HTTPS and header setup.

Checks one page · Free · No sign-up needed

How to set cookie flags on common platforms

  • PHP sessions: in php.ini, set session.cookie_secure = 1, session.cookie_httponly = 1 and session.cookie_samesite = "Lax" (PHP 7.3 and later), or pass the same options to session_set_cookie_params().
  • Django: SESSION_COOKIE_SECURE = True and CSRF_COOKIE_SECURE = True. SESSION_COOKIE_HTTPONLY and SESSION_COOKIE_SAMESITE = "Lax" are already the defaults.
  • Express (Node.js): res.cookie("sid", value, { secure: true, httpOnly: true, sameSite: "lax" }), or the cookie options of express-session. Behind a proxy, enable trust proxy so Express knows the connection is HTTPS.
  • WordPress: core login cookies are HttpOnly, and marked Secure when the site runs on HTTPS. Plugin cookies vary; check them in developer tools and ask the plugin's authors if they lack flags.
  • Reverse proxy as a last resort: nginx's proxy_cookie_flags (1.19.3 and later) can add secure, httponly and samesite to cookies from an application you can't change.

Common mistakes

  • Marking cookies Secure in production but testing only over HTTP locally, then disabling the flag "temporarily".
  • Setting SameSite=None without Secure, so browsers drop the cookie and a login or embed stops working.
  • Scoping session cookies to the parent domain "just in case".
  • Storing session tokens in localStorage, where any injected script can read them — HttpOnly cookies are safer.
  • Putting personal data in cookie values. Cookies should hold identifiers, not information.

Cookies are one part of the picture. For headers, HTTPS and the limits of passive testing, read how to check website security.

Frequently asked questions

Should every cookie be HttpOnly?

Every cookie that JavaScript doesn't need to read should be. Session and authentication cookies should always be HttpOnly. Preference cookies or tokens that your front-end code reads deliberately can't be, which is fine.

Is SameSite=Lax enough to prevent CSRF?

It blocks the most common cross-site form posts, but it isn't a complete defence on its own: same-site subdomains and top-level GET requests can still carry the cookie. Keep CSRF tokens for state-changing requests, and never change data with GET.

Why does my cookie disappear when I set SameSite=None?

Browsers reject SameSite=None cookies that aren't also marked Secure. Add Secure and serve the site over HTTPS.

Does Rudra read my cookie values?

No. The security checker records cookie names and their attributes only. Values, tokens and anything else inside a cookie are never read, stored or shown.

Keep reading

Find out what's holding your website back

Run a free check on any public page. No sign-up needed for a basic check.