When someone successfully logs into a website, the server typically issues a session cookie—a small identifier stored in the browser. This cookie allows users to avoid entering their password on every page.
The problem is that anyone who obtains that session can potentially act as if they are the legitimate user. Therefore, login security does not stop at passwords and HTTPS. Cookie attributes, session expiration, ID regeneration after login, and logout handling also need to be considered.
Why is it necessary to secure session cookies?
Think of a session cookie like an access wristband in a building. The staff do not always ask for identification in every room; they just look at the wristband. If the wristband changes hands, someone else can gain the same access.
In web applications, this risk is known as session hijacking, which is the takeover of a user's session. Leaks can occur through insecure connections, XSS vulnerabilities, infected devices, logs storing tokens, or cookies with overly broad scopes.
OWASP recommends long, random, and hard-to-guess session IDs. Sessions should also have timeouts, be regenerated after authentication, and should never be placed in URLs because URLs can easily enter browser history, server logs, or analytics services.
Three cookie attributes that should not be forgotten
1. Secure
The Secure attribute ensures that the browser only sends cookies over HTTPS connections. This is important even when the website redirects HTTP to HTTPS. Without this attribute, there are certain scenarios where the browser may still send cookies over unencrypted connections.
2. HttpOnly
HttpOnly prevents JavaScript in the browser from reading cookies directly. This attribute does not solve all XSS issues, but it can limit the impact when a malicious script successfully enters the page.
3. SameSite
SameSite controls whether cookies can be sent in the context of cross-site requests. The Lax value is usually a practical choice for many websites, while Strict imposes stricter limitations but may affect login flows from external links or certain integrations.
For highly sensitive sessions, strict configurations like Secure, HttpOnly, and SameSite=Strict should be considered after testing across the entire application flow.
Example session configuration in PHP
PHP provides session_set_cookie_params() to set cookie attributes before the session starts. A simple example is:
<?php
session_set_cookie_params([
'lifetime' => 0,
'path' => '/',
'secure' => true,
'httponly' => true,
'samesite' => 'Lax'
]);
session_start();
?>A lifetime value of 0 means the cookie is valid for the duration of the browser session. For applications with different needs, the expiration can be adjusted. However, do not keep admin login sessions active indefinitely just for convenience.
This configuration is only effective if the website is truly running over HTTPS. In local development environments that do not use HTTPS, setting secure=true may cause the browser not to send the cookie. Use separate configurations for development and production, rather than disabling protections on the production server.
Regenerate session ID after login
One important step is to regenerate the session ID after the user successfully logs in. The goal is to prevent session fixation, which is a situation where an attacker knows or influences the session ID before the victim logs in.
if (password_verify($password, $user['password_hash'])) {
session_regenerate_id(true);
$_SESSION['user_id'] = $user['id'];
$_SESSION['logged_in'] = true;
}Regenerating the ID is also advisable when a user escalates privileges, for example, from a regular user to an administrator. After logout, clear session data on the server and instruct the browser to delete the related cookie.
What about WordPress?
In WordPress, website owners do not need to create their own session system for standard logins. The main focus should be on updating the WordPress core, plugins, themes, PHP, and server components. Plugins or themes from untrusted sources can introduce vulnerabilities even if the hosting configuration is good.
Use HTTPS thoroughly, limit the number of administrator accounts, remove unused plugins, and avoid using the same credentials across multiple services. If a plugin provides cookie or login settings, read its documentation before changing the default values.
WordPress also emphasizes the importance of backups that are truly recoverable. Backups are not just files stored; perform periodic restore tests to ensure that the backup is intact when incidents occur.
Checklist to implement now
- Ensure the login page, dashboard, and entire website use HTTPS.
- Check session cookies in the browser's Developer Tools. Look for
Secure,HttpOnly, andSameSiteattributes. - Do not send session IDs via URL parameters.
- Regenerate session IDs after login and privilege changes.
- Set idle timeouts and maximum session age for sensitive accounts.
- Clear active sessions when users log out or change passwords.
- Regularly update WordPress, plugins, themes, PHP, and server software.
- Store database and website file backups in different locations, then test their recovery.
What does this mean for us?
Session security is not an additional feature only needed by large companies. Small store websites, blogs with admin areas, and internal applications all have sessions that can be exploited.
Measures like HttpOnly, Secure, SameSite, ID regeneration, and tested backups may not be visible to visitors. However, it is precisely these small layers that reduce the chances of a simple mistake turning into an account takeover or costly website recovery.
For advanced technical guidance, refer to the OWASP documentation on cookie attributes, the PHP manual on session cookies, and the WordPress hardening guide.
Sources & further reading
- OWASP Web Security Testing Guide: Testing for Cookie Attributes
- PHP Manual: session_set_cookie_params
- WordPress Developer Resources: Hardening WordPress
- WordPress Developer Resources: Backups
- OWASP SameSite Cookie Attribute Guidance
– Rio Yotto @rioyotto
