When someone successfully logs in, websites typically do not ask for a password on every page. The browser stores a session cookie—a marker that informs the server that the user is authenticated. If this cookie leaks or is sent in the wrong context, an attacker could exploit it to act as that user.
Therefore, login security does not stop at a strong password. Cookie attributes such as Secure, HttpOnly, and SameSite are important layers of defense. However, each has a different function and should not be considered a magic button that solves all problems. ([cheatsheetseries.owasp.org](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html?utm_source=openai))
Three Attributes to Understand
1. Secure: Send Only Over HTTPS
The Secure attribute ensures that the browser only sends the cookie over HTTPS connections. This helps prevent the session ID from being read when network traffic is intercepted, for example, when a user is using public Wi-Fi.
It is important to note that simply having HTTPS is not enough if the cookie does not have the Secure attribute. Without this attribute, the browser may send the cookie over HTTP under certain conditions. Therefore, websites that operate solely over HTTPS should consistently set Secure. ([cheatsheetseries.owasp.org](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html?utm_source=openai))
2. HttpOnly: Limit Access from JavaScript
HttpOnly prevents the cookie from being read via document.cookie. This reduces the impact of certain XSS scenarios, where malicious scripts successfully run on the website page.
This attribute does not mean that XSS is rendered harmless. The browser will still automatically send the cookie when a script makes a request to the same website. This means that HttpOnly helps protect the confidentiality of the cookie, but does not replace XSS prevention, input validation, or Content Security Policy. ([cheatsheetseries.owasp.org](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html?utm_source=openai))
3. SameSite: Control Cross-Site Requests
SameSite informs the browser when the cookie can be sent on requests originating from other sites. The Strict value is the most stringent, while Lax usually offers a more convenient compromise for general websites. The None value allows cross-site sending and must be accompanied by Secure.
SameSite is useful as an additional defense against CSRF, but it is not a substitute for CSRF tokens. For example, the Lax mode still allows some top-level navigation with safe methods like GET. Therefore, endpoints that modify data should not use GET, and critical operations still need to be protected by CSRF tokens or other verification mechanisms. ([cheatsheetseries.owasp.org](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html?utm_source=openai))
Example PHP Configuration
For a simple PHP application, session cookie settings should be done before session_start(). The following example is suitable as a starting point for websites that operate entirely over HTTPS:
<?php
session_set_cookie_params([
'lifetime' => 0,
'path' => '/',
'domain' => '',
'secure' => true,
'httponly' => true,
'samesite' => 'Lax'
]);
session_start();
lifetime set to zero means the session cookie typically expires when the browser is closed. This may not be suitable for a “remember me” feature, but it is safer than allowing a login session to persist indefinitely. For high-risk applications, idle time and session duration should also be limited on the server side.
PHP supports setting secure, httponly, and samesite through session_set_cookie_params(). If options are not set, certain attributes may not be sent at all, causing the browser's behavior to depend on the configuration and defaults in effect. ([php.net](https://www.php.net/session-set-cookie-params?utm_source=openai))
Do Not Expand Cookies Without Reason
One configuration that is often overlooked is Domain. If a cookie is created for example.com, that cookie can be sent to subdomains like blog.example.com and admin.example.com. This may be necessary in certain architectures, but it also increases the risk area: vulnerabilities in one subdomain could potentially affect cookies used by other applications.
If the session is only used by one host, it is usually safer not to set the Domain attribute. For cookies that are only valid on a specific host and across the entire path, the prefix __Host- can be considered. This prefix requires HTTPS, does not use Domain, and uses Path=/. ([cheatsheetseries.owasp.org](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html?utm_source=openai))
Example of a stricter header:
Set-Cookie: __Host-SessionID=random-value; Path=/; Secure; HttpOnly; SameSite=LaxCommon Implementation Mistakes
- Storing login tokens in localStorage. Data in Web Storage can be read by JavaScript on the same origin. If XSS occurs, tokens may be exposed. For browser sessions, HttpOnly cookies are more appropriate in many scenarios. ([cheatsheetseries.owasp.org](https://cheatsheetseries.owasp.org/cheatsheets/Session_Management_Cheat_Sheet.html?utm_source=openai))
- Using GET to modify data. URLs like
/delete-account?id=123can be called from various contexts and are at risk of being triggered accidentally. Use POST, PUT, PATCH, or DELETE as needed, and then add CSRF protection. - Assuming logout only removes cookies. Sessions also need to be disabled on the server. If the old session ID is still valid, a previously stolen cookie may still be usable.
- Allowing old sessions after login or privilege changes. Regenerate the session ID after authentication and when privilege changes occur. This way, IDs that may have been known before login are not reused.
- Enabling SameSite=Strict without testing business flows. The strictest settings can disrupt login flows from emails, payments, or third-party integrations. Choose configurations based on needs, not just to pursue the strictest value.
What You Can Do Now
- Open the browser's Developer Tools, check the Application or Storage tab, and then view the session cookies.
- Ensure that authentication cookies have
SecureandHttpOnly. - Ensure that
SameSiteis explicitly set toLaxorStrict, not left undecided. - Check if the
Domainattribute is truly necessary. If not, remove it. - Test login, logout, password changes, email changes, and privilege escalations. Ensure that the session ID is regenerated at critical moments.
- Audit endpoints that modify data. There should be no destructive actions relying solely on
GETrequests.
In Summary
Login cookies are a temporary key to a user's account. Secure protects them when sent over the network, HttpOnly limits reading from JavaScript, and SameSite helps reduce unwanted cross-site requests. All three work better when combined with HTTPS, XSS prevention, CSRF tokens, session ID rotation, and proper logout that truly ends the session on the server.
If you manage a WordPress website or an older PHP application, checking cookies is a small step with significant benefits. There’s no need to wait for an incident to find out that session cookies are being sent without basic protections.
Sources & Further Reading
- OWASP Session Management Cheat Sheet
- MDN: Set-Cookie header
- MDN: Secure cookie configuration
- PHP Manual: session_set_cookie_params
- OWASP Cross-Site Request Forgery Prevention Cheat Sheet
– Rio Yotto @rioyotto
