fkooman/secookie

Secure cookie and session library


Keywords
cookie, php, security, session
License
MIT

Documentation

Scrutinizer Code Quality

Introduction

Secure Cookie and Session library for PHP.

Why

  • PHP >= 5.4 support for CentOS 7;
  • Replace complicated setcookie() which is not secure by default (HttpOnly, Secure, SameSite are not the default);
  • delight-im/cookie and paragonie/cookie, in addition to requiring PHP >= 5.6, parse cookies, which is best avoided for security reasons;
  • Allow binding PHP Sessions to "Domain" and "Path" (see below);
  • Easy to use PHP Session API;
  • Uses a "Canary" to regularly refresh session ID;
  • Expires the PHP Session on the server;
  • Implements Same-Site attribute value;
  • Unit tests with PHPUnit;

Many of the ideas came from the resources below, delight-im/cookie and Airship's implementation of (secure) sessions.

We do NOT support the (deprecated) Expires attribute value as Max-Age is supported by all current, i.e. >= IE 11, browsers on desktop and mobile.

Cookies

Setting a cookie, i.e. add the Set-Cookie header is straightforward:

$cookie = new Cookie();
$cookie->set('foo', 'bar');

This will set the cookie using the Secure, HttpOnly and SameSite=Strict values.

The following configuration options are supported:

  • Secure: bool (default: true)
  • HttpOnly: bool (default: true)
  • Path: string|null (default: null)
  • Domain: string|null (default: null)
  • Max-Age: int|null (default: null)
  • SameSite: Strict|Lax|null (default: Strict)

For example, to limit a browser to only send the cookie to the /foo/ path and use the Lax option for SameSite:

$cookie = new Cookie(
    [
        'Path' => '/foo/',
        'SameSite' => 'Lax',
    ]
);
$cookie->set('foo', 'bar');

You can delete a cookie, i.e. set the value to "" by using the delete() method:

$cookie->delete('foo');

Sessions

Sessions will use the same defaults as Cookies, so you'll get secure sessions out of the box.

$session = new Session();
$session->set('foo', 'bar');

Note that the values here are stored inside the session, and not sent to the browser!

The following configuration options are supported, in addition to the ones already mentioned in the Cookie section:

  • DomainBinding: string|null (default: null), see "Session Binding"
  • PathBinding: string|null (default: null), see "Session Binding"
  • SessionExpiry: string (default: PT08H, 8 hours), see "Session Expiry"
  • CanaryExpiry: string (default: PT01H, 1 hour)
  • SessionName: string|null (default: null)

The format for SessionExpiry and CanaryExpiry are any string that is accepted by PHP's DateInterval class.

You can destroy a session, i.e. empty the $_SESSION variable and regenerate the session ID by calling the destroy() method:

$session->destroy();

You can regenerate the session ID:

$session->regenerate();

It accepts a boolean parameter to delete the session on the server.

In addition there are methods for get(), set(), has() and delete() as well. It is recommended to call regenerate() before storing important information in the session, for example after user authentication.

Session Binding

Session binding is implemented to avoid using a PHP Session meant for one "Domain" or "Path" being used at another Domain or Path. This is important if you are hosting a "multi-site" application where the site is running at multiple domains, but shares the same PHP session storage.

This can be used like this:

$session = new Session(
    [
        'DomainBinding' => 'www.example.org',
        'PathBinding' => '/foo/',
    ]
);

This does not restrict the Domain and Path options for the Cookie, to modify these you'd have to also specify the Domain and Path options, but leaving them empty can result in more secure cookies as they will be automatically bound to the "Path" and "Domain" that set them, see The definitive guide to cookie domains and why a www-prefix makes your website safer linked in the resources below.

Session Expiry

The PHP Session typically lives as long as the user's user agent, i.e. browser, runs. On many platforms the browser is not closed anymore and remains open indefinitely, or as least until the device is restarted, e.g. on mobile.

For some use cases it may be necessary to expire sessions on the server, this can be done with the SessionExpiry configuration option. The default is 8 hours.

$session = new Session(
    [
        'SessionExpiry' => 'PT08H',
    ]
);

To disable session expiry, you can set the SessionExpiry to null.

Security

It is very important that you update your PHP Session settings in php.ini on your host. See The Fast Track to Safe and Secure PHP Sessions, linked below in the resources.

;
; session
;
; @see https://paragonie.com/blog/2015/04/fast-track-safe-and-secure-php-sessions
; @see https://secure.php.net/manual/en/session.configuration.php
;
session.save_handler = files
session.save_path = "/var/lib/php/session"
session.use_cookies = 1
session.use_only_cookies = 1

; PHP < 7.1
session.hash_function = sha256
session.hash_bits_per_character = 5
session.entropy_file = /dev/urandom
session.entropy_length = 32

; PHP >= 5.5.2
;session.use_strict_mode = 1

; PHP >= 7.1
;session.sid_length = 52
;session.sid_bits_per_character = 5

Resources