pics/models/Session.php
Aaron van Geffen a208c0482f Invoke Dispatcher::kickGuest from Session for invalid sessions.
Previously, a NotAllowedException would be thrown if an invalid session
was encountered. However, these exceptions were not caught, and hence
would yield a fatal uncaught exception error.

At this point in Kabuki, the ErrorHandler class has not been registered yet
for error handling purposes. This error is therefore not visible if the PHP
ini directive 'display_errors' is set to 'Off'. As this is the default
production value, the script would fail with a blank page in such cases.
2020-03-11 22:38:15 +01:00

90 lines
3.6 KiB
PHP

<?php
/*****************************************************************************
* Session.php
* Contains the key class Session.
*
* Kabuki CMS (C) 2013-2015, Aaron van Geffen
*****************************************************************************/
class Session
{
public static function start()
{
session_start();
// Resuming an existing session? Check what we know!
if (isset($_SESSION['user_id'], $_SESSION['ip_address'], $_SESSION['user_agent']))
{
// If we're not browsing over HTTPS, protect against session hijacking.
if (!isset($_SERVER['HTTPS']) && isset($_SERVER['REMOTE_ADDR']) && $_SESSION['ip_address'] !== $_SERVER['REMOTE_ADDR'])
{
$_SESSION = [];
Dispatcher::kickGuest('Your session failed to validate', 'Your IP address has changed. Please re-login and try again.');
}
// Either way, require re-login if the browser identifier has changed.
elseif (isset($_SERVER['HTTP_USER_AGENT']) && $_SESSION['user_agent'] !== $_SERVER['HTTP_USER_AGENT'])
{
$_SESSION = [];
Dispatcher::kickGuest('Your session failed to validate', 'Your browser identifier has changed. Please re-login and try again.');
}
}
elseif (!isset($_SESSION['ip_address'], $_SESSION['user_agent']))
$_SESSION = [
'ip_address' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '',
'user_agent' => isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '',
];
return true;
}
public static function resetSessionToken()
{
$_SESSION['session_token'] = sha1(session_id() . mt_rand());
$_SESSION['session_token_key'] = substr(preg_replace('~^\d+~', '', sha1(mt_rand() . session_id() . mt_rand())), 0, rand(7, 12));
return true;
}
public static function validateSession($method = 'post')
{
// First, check whether the submitted token and key match the ones in storage.
if (($method === 'post' && (!isset($_POST[$_SESSION['session_token_key']]) || $_POST[$_SESSION['session_token_key']] !== $_SESSION['session_token'])) ||
($method === 'get' && (!isset($_GET[$_SESSION['session_token_key']]) || $_GET[$_SESSION['session_token_key']] !== $_SESSION['session_token'])))
throw new UserFacingException('Session failed to verify (' . $method . '). Please reload the page and try again.');
// Check the referring site, too -- should be the same site!
$referring_host = isset($_SERVER['HTTP_REFERER']) ? parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST) : '';
if (!empty($referring_host))
{
if (strpos($_SERVER['HTTP_HOST'], ':') !== false)
$current_host = substr($_SERVER['HTTP_HOST'], 0, strpos($_SERVER['HTTP_HOST'], ':'));
else
$current_host = $_SERVER['HTTP_HOST'];
$base_url_host = parse_url(BASEURL, PHP_URL_HOST);
// The referring_host must match either the base_url_host or the current_host.
if (strtolower($referring_host) !== strtolower($base_url_host) && strtolower($referring_host) !== strtolower($current_host))
throw new UserFacingException('Invalid referring URL. Please reload the page and try again.');
}
// All looks good from here! But you can only use this token once, so...
return self::resetSessionToken();
}
public static function getSessionToken()
{
if (empty($_SESSION['session_token']))
trigger_error('Call to getSessionToken without a session token being set!', E_USER_ERROR);
return $_SESSION['session_token'];
}
public static function getSessionTokenKey()
{
if (empty($_SESSION['session_token_key']))
trigger_error('Call to getSessionTokenKey without a session token key being set!', E_USER_ERROR);
return $_SESSION['session_token_key'];
}
}