Pragmatism in the real world

Validating default PHP session ID values

I recently needed to validate the value created by PHP for its session ID. After a bit of research, I realised that there are two interesting php.ini config settings that relate to this value:

  • session.sid_length is the number of characters in the ID
  • session.sid_bits_per_character controls the set of characters used. From the manual:

    The possible values are ‘4’ (0-9, a-f), ‘5’ (0-9, a-v), and ‘6’ (0-9, a-z, A-Z, “-“, “,”).

Therefore, to validate the session ID we need to create a regular expression that looks for the correct set of characters of the expected length.

I wrote function to do this:

function isValidSessionId(string $sessionId): bool
{
    $sidLength = ini_get('session.sid_length');

    switch (ini_get('session.sid_bits_per_character')) {
        case 6:
            $characterClass = '0-9a-zA-z,-';
            break;
        case 5:
            $characterClass = '0-9a-v';
            break;
        case 4:
            $characterClass = '0-9a-f';
            break;
        default:
            throw new \RuntimeException('Unknown value in session.sid_bits_per_character.');
    }
    $pattern = '/^[' . $characterClass . ']{' . $sidLength . '}$/';

    return preg_match($pattern, $sessionId) === 1;
} 

You could use it like this:

$name = session_name();
if (isset($_COOKIE[$name])) {
    if (!isValidSessionId($_COOKIE[$name])) {
        // invalid - return an error, just send back a 500 or something
        exit;
    }
}

As far as I can tell, we can’t use session_id() as we haven’t started the session yet, however as the session is just a cookie at the HTTP level, we can use $_COOKIE instead.

Note also that the manual has an excellent section on Sessions and Security which is worth reading.

7 thoughts on “Validating default PHP session ID values

  1. This seems interesting. But I'm curious, what was the scenario where you needed to validate a session ID? I couldn't think of anything right off the top of head that fit that need.

    Thanks

  2. Rather than using switch/case, you could use a look-up table in your isValidSessionId() function, like:

    function isValidSessionId(string $sessionId): bool
    {
    if (empty($sessionId)) {
    return false;
    }

    $sidLength = ini_get('session.sid_length');
    $bitsPerCharacter = ini_get('session.sid_bits_per_character');
    $characterClass = [
    6 => '0-9a-zA-z,-',
    5 => '0-9a-z',
    4 => '0-9a-f'
    ];

    if (array_key_exists($bitsPerCharacter, $characterClass)) {
    $pattern = '/^[' . $characterClass . ']{' . $sidLength . '}$/';
    return preg_match($pattern, $sessionId) === 1;
    }
    throw new \RuntimeException('Unknown value in session.sid_bits_per_character.');
    }

Comments are closed.