Home / Articles / Web Security
Web Security

Secure Login Is More Than Just a Password: Streamline Website Session Management

Many websites already use HTTPS and strong passwords, but still carry risks with overly lax login sessions. Understand how session cookies work, session fixation, and PHP settings that can be improved without ha...

Login Aman Bukan Hanya Soal Password: Rapikan Pengelolaan Sesi Website

Users often think that login security is complete once the password is successfully verified. However, after logging in, the website still needs to maintain the "identifier" used to recognize the user on each subsequent request. This identifier usually takes the form of a session ID in a cookie.

If the session ID is stolen, set before login, or left valid for too long, an attacker does not need to know the password to take over the session. Therefore, session management should be treated like a house key: it should not only be difficult to duplicate, but also need to be restricted in terms of when, where, and how the key is used.

Understanding login sessions with a simple analogy

Imagine you enter a building and receive an access card. The officer checks your identity once, and then the card is used to open certain doors while you are inside the building.

On a website, the password is used during the authentication process. After that, the server provides a session ID to the browser. The browser sends this ID on the next request so the server knows that the user is logged in.

Problems arise when the access card:

  • can be read by any script in the browser;
  • remains valid over unencrypted HTTP connections;
  • is not changed after the user successfully logs in;
  • is accepted even if created by another party; or
  • never expires and is not actually revoked upon logout.

This is why session security should not be considered a minor detail behind the scenes.

Three cookie attributes that should be standard

For session cookies, three basic attributes need to be checked: Secure, HttpOnly, and SameSite.

1. Secure: only over HTTPS

The Secure attribute instructs the browser to send cookies only over HTTPS connections. This helps prevent session IDs from being exposed when network traffic is intercepted, especially on public Wi-Fi or networks that are not fully trusted.

However, Secure is not a substitute for HTTPS. Websites still need to redirect all pages to HTTPS and, if appropriate for their infrastructure, use HSTS to prevent the browser from attempting HTTP connections again.

2. HttpOnly: not readable by JavaScript

HttpOnly prevents cookies from being read via document.cookie. This limits the impact of cookie theft in some XSS scenarios.

It is important to note that this attribute does not make XSS harmless. Malicious JavaScript can still send requests from the victim's browser, and the browser will still include cookies in those requests. Therefore, XSS prevention and CSRF protection are still necessary.

3. SameSite: limit cross-site sending

SameSite=Strict or SameSite=Lax helps limit when cookies are sent in requests originating from other sites. This provides an additional layer of defense against CSRF, which is an attack that exploits the victim's login session to send actions without consent.

For regular applications that do not require cross-site flows, Strict is often the most stringent choice. If users need to log in from external links or there are specific compatibility needs, Lax can be a more practical compromise. Whatever the choice, do not rely on the browser's default values without checking the application's behavior.

Do not accept session IDs from URLs

Session IDs appearing in URLs are more easily leaked through browser history, server logs, bookmarks, or referer headers. A suspicious example is an address like /dashboard?session_id=abc123.

Use cookies as the sole mechanism for exchanging session IDs. If the application accepts IDs from both the URL and cookies, attackers have more avenues to inject or force specific session values.

Also, use clear cookie names and scopes. For applications running on a single host, patterns like the following can help narrow the cookie's scope:

Set-Cookie: __Host-SessionID=random-value; Secure; HttpOnly; SameSite=Lax; Path=/

The __Host- prefix requires the cookie to use HTTPS, not have a Domain attribute, and use Path=/. This is not a solution for all architectures, but it is useful when cookies do not need to be shared with other subdomains.

Regenerate session ID after login

One critical mistake is maintaining the same session ID before and after authentication. This condition opens the door to session fixation: an attacker knows or sets the session ID first, and then the victim logs in using that session.

The solution is conceptually simple: regenerate the session ID after a successful login and after any change in access rights. Valid session data needs to be retained, but the session identifier must be changed.

A simple example in PHP:

<?php
session_start();

// After username and password are successfully verified
session_regenerate_id(true);
$_SESSION['user_id'] = $userId;
$_SESSION['logged_in_at'] = time();
?>

In real applications, ensure that the regeneration process does not cause race conditions or delete session data that is still needed. Test the login, logout, password change, and login from multiple tabs flows before deploying to production.

Often overlooked PHP settings

PHP provides several settings that can tighten session management. One of them is session.use_strict_mode, which helps reject session IDs that were never created by the server. Cookie settings should also be enforced from the server side, rather than relying solely on application code that may be inconsistent.

session.use_strict_mode = 1
session.use_only_cookies = 1
session.cookie_secure = 1
session.cookie_httponly = 1
session.cookie_samesite = Lax

Configuration names and support may vary depending on the PHP version and deployment method. Check the documentation for the PHP version in use, and then test in staging before changing production configurations.

Logout must truly end the session

Removing the account view from the page does not necessarily end the session on the server. Upon logout, delete session data on the server, invalidate cookies, and consider clearing the cache on sensitive pages.

For accounts with high risk, sessions should also be terminated or require re-authentication after events such as password changes, email address changes, account recovery, or suspicious activity from new devices.

Checklist for immediate review

  1. Open the browser's DevTools and check session cookies: do they have Secure, HttpOnly, and SameSite?
  2. Ensure session IDs do not appear in URLs, HTML, application logs, or analytics parameters.
  3. Compare session IDs before and after login. Their values should change.
  4. Test whether the Back button still displays sensitive data after logout.
  5. Check if old sessions become invalid after the password is changed.
  6. Ensure authentication tokens are not stored in localStorage if HttpOnly cookies can be used.

Session security does not require major changes to start improving. Begin with cookie attributes, ID regeneration after login, PHP strict mode, and logout testing. These four steps often provide significant improvements before the team delves into larger tasks like device management, anomaly detection, and risk-based re-authentication.

Sources & further reading

Explore also

– Rio Yotto @rioyotto