Skip to content

PHP Tutorial Sessions and Cookies

Secure Session Practices

Lesson 185 of 369 2 min read By Deepak Paswan Updated Oct 5, 2026

A session ID works like a key to a user’s account. If an attacker steals or guesses it, they can pretend to be that user. These habits keep the key safe.

index.php
PHP
<?php
session_set_cookie_params([
    "lifetime" => 0,          // until the browser closes
    "path" => "/",
    "secure" => true,         // HTTPS only
    "httponly" => true,       // JavaScript cannot read it
    "samesite" => "Lax",      // limits cross-site sending
]);

session_start();
  • HttpOnly stops scripts from reading the ID, so an XSS bug cannot steal it directly.
  • Secure keeps the cookie off unencrypted connections.
  • SameSite reduces the risk of CSRF.

2. Strict mode

index.php
PHP
<?php
ini_set("session.use_strict_mode", "1");
ini_set("session.use_only_cookies", "1");
  • use_strict_mode refuses a session ID that the server did not create. That helps against session fixation.
  • use_only_cookies stops session IDs from being accepted in a URL (?PHPSESSID=...), where they leak through logs and the Referer header.

3. Regenerate the ID at login

Create a new ID whenever the user logs in or gains privileges. The old ID becomes useless.

index.php
PHP
<?php
session_regenerate_id(true);   // true deletes the old session data
$_SESSION["user_id"] = $user["id"];

See Session Fixation for the attack this prevents.

4. Timeouts

Log people out after a period of inactivity, and set an absolute limit too.

index.php
PHP
<?php
function sessionIsValid(array $session, int $now, int $idle = 1800, int $absolute = 28800): bool
{
    return ($now - ($session["last_activity"] ?? 0)) <= $idle
        && ($now - ($session["started_at"] ?? 0)) <= $absolute;
}

$session = ["started_at" => 1000, "last_activity" => 2000];

var_dump(sessionIsValid($session, 2500));     // 500 seconds idle
var_dump(sessionIsValid($session, 9000));     // 7000 seconds idle
Output
OUTPUT
bool(true)
bool(false)

5. Store little, and nothing secret

Keep an ID and a few flags. If the session store is ever exposed, there should be little to steal.

6. A safe start function

index.php
PHP
<?php
function startSecureSession(): void
{
    if (session_status() !== PHP_SESSION_NONE) {
        return;
    }

    ini_set("session.use_strict_mode", "1");
    ini_set("session.use_only_cookies", "1");

    session_set_cookie_params([
        "lifetime" => 0,
        "path" => "/",
        "secure" => !empty($_SERVER["HTTPS"]) && $_SERVER["HTTPS"] !== "off",
        "httponly" => true,
        "samesite" => "Lax",
    ]);

    session_start();

    $now = time();
    $_SESSION["started_at"] ??= $now;

    if (($now - ($_SESSION["last_activity"] ?? $now)) > 1800) {
        $_SESSION = [];
        session_regenerate_id(true);
        $_SESSION["started_at"] = $now;
    }

    $_SESSION["last_activity"] = $now;
}

7. Use HTTPS everywhere

Without HTTPS, anyone on the same network can read the session cookie. Redirect all traffic to HTTPS and consider the Strict-Transport-Security header.

8. Logout properly

Clear $_SESSION, expire the cookie and call session_destroy(). See Destroying a Session.

9. Do not rely on the IP address or User-Agent

Binding a session to an IP address breaks for people on mobile networks, whose address changes. A User-Agent check is easy to fake. They add little protection and can lock out real users.

Quick checklist

  • httponly, secure, samesite on the cookie
  • Strict mode and cookies only
  • New ID at login and privilege changes
  • Idle and absolute timeouts
  • Small, non-secret session data
  • HTTPS and a clean logout
info
Why this matters in WordPress and Laravel
WordPress uses its own cookies and tokens, and Laravel has a session system with the same ideas built in (regeneration at login, secure cookie flags, timeouts). Knowing the plain PHP version helps you understand and configure them.