mirror of
https://github.com/Lastorder-DC/rhymix.git
synced 2026-01-06 10:11:38 +09:00
Remove session keys, and always set httpOnly
This commit is contained in:
parent
c53e0a93f5
commit
60a3edc994
2 changed files with 41 additions and 171 deletions
|
|
@ -1032,7 +1032,7 @@ class ModuleHandler extends Handler
|
|||
// Handle redirects.
|
||||
if($oModule->getRedirectUrl())
|
||||
{
|
||||
if ($_SESSION['is_new_session'])
|
||||
if (!empty($_SESSION['is_new_session']))
|
||||
{
|
||||
ob_end_clean();
|
||||
echo sprintf('<html><head><meta charset="UTF-8" /><meta http-equiv="refresh" content="0; url=%s" /></head><body></body></html>', escape($oModule->getRedirectUrl()));
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ class Session
|
|||
ini_set('session.use_strict_mode', 1);
|
||||
if ($samesite)
|
||||
{
|
||||
if (version_compare(PHP_VERSION, '7.3', '>='))
|
||||
if (PHP_VERSION_ID >= 70300)
|
||||
{
|
||||
ini_set('session.cookie_samesite', $samesite);
|
||||
}
|
||||
|
|
@ -90,7 +90,7 @@ class Session
|
|||
$path = ($path ?: '/') . '; SameSite=' . $samesite;
|
||||
}
|
||||
}
|
||||
session_set_cookie_params($lifetime, $path, $domain, $secure, $secure);
|
||||
session_set_cookie_params($lifetime, $path, $domain, $secure, true);
|
||||
session_name($session_name = Config::get('session.name') ?: session_name());
|
||||
|
||||
// Check if the session cookie already exists.
|
||||
|
|
@ -114,11 +114,7 @@ class Session
|
|||
|
||||
// Mark the session as started.
|
||||
self::$_started = true;
|
||||
|
||||
// Fetch session keys.
|
||||
list($key1, $key2, self::$_autologin_key) = self::_getKeys();
|
||||
$must_create = $must_refresh = $must_resend_keys = false;
|
||||
$check_keys = config('session.use_keys');
|
||||
$must_create = $must_refresh = false;
|
||||
|
||||
// Check whether the visitor uses Android webview.
|
||||
if (!isset($_SESSION['is_webview']))
|
||||
|
|
@ -126,66 +122,14 @@ class Session
|
|||
$_SESSION['is_webview'] = self::_isBuggyUserAgent();
|
||||
}
|
||||
|
||||
// Validate the HTTP key.
|
||||
if (isset($_SESSION['RHYMIX']) && $_SESSION['RHYMIX'])
|
||||
{
|
||||
if (!isset($_SESSION['RHYMIX']['keys'][$alt_domain]) && config('use_sso'))
|
||||
{
|
||||
$must_refresh = true;
|
||||
}
|
||||
elseif ($_SESSION['RHYMIX']['keys'][$alt_domain]['key1'] === $key1 && $key1 !== null)
|
||||
{
|
||||
// OK
|
||||
}
|
||||
elseif ($_SESSION['RHYMIX']['keys'][$alt_domain]['key1_prev'] === $key1 && $key1 !== null)
|
||||
{
|
||||
$must_resend_keys = true;
|
||||
}
|
||||
elseif ($check_keys && !$_SESSION['is_webview'])
|
||||
{
|
||||
// Hacked session! Destroy everything.
|
||||
trigger_error('Session is invalid (missing key 1)', \E_USER_WARNING);
|
||||
$_SESSION = array();
|
||||
$must_create = true;
|
||||
self::destroyAutologinKeys();
|
||||
}
|
||||
}
|
||||
else
|
||||
// Check if the session has been initialized for Rhymix.
|
||||
if (!isset($_SESSION['RHYMIX']))
|
||||
{
|
||||
$must_create = true;
|
||||
}
|
||||
|
||||
// Validate the SSL key.
|
||||
if (!$must_create && \RX_SSL)
|
||||
{
|
||||
if (!isset($_SESSION['RHYMIX']['keys'][$alt_domain]['key2']))
|
||||
{
|
||||
$must_refresh = true;
|
||||
}
|
||||
elseif ($_SESSION['RHYMIX']['keys'][$alt_domain]['key2'] === $key2 && $key2 !== null)
|
||||
{
|
||||
// OK
|
||||
}
|
||||
elseif ($_SESSION['RHYMIX']['keys'][$alt_domain]['key2_prev'] === $key2 && $key2 !== null)
|
||||
{
|
||||
$must_resend_keys = true;
|
||||
}
|
||||
elseif ($check_keys && !$_SESSION['is_webview'])
|
||||
{
|
||||
// Hacked session! Destroy everything.
|
||||
trigger_error('Session is invalid (missing key 2)', \E_USER_WARNING);
|
||||
$_SESSION = array();
|
||||
$must_create = true;
|
||||
self::destroyAutologinKeys();
|
||||
}
|
||||
}
|
||||
|
||||
// Check the refresh interval.
|
||||
if (!$must_create && $_SESSION['RHYMIX']['keys'][$alt_domain]['key1_time'] < time() - $refresh_interval && $check_keys)
|
||||
{
|
||||
$must_refresh = true;
|
||||
}
|
||||
elseif (!$must_create && \RX_SSL && $_SESSION['RHYMIX']['keys'][$alt_domain]['key2_time'] < time() - $refresh_interval && $check_keys)
|
||||
// Check if the session needs to be refreshed.
|
||||
if (!$must_create && !isset($_SESSION['RHYMIX']['domains'][$alt_domain]['started']) || $_SESSION['RHYMIX']['domains'][$alt_domain]['started'] < time() - $refresh_interval)
|
||||
{
|
||||
$must_refresh = true;
|
||||
}
|
||||
|
|
@ -228,10 +172,6 @@ class Session
|
|||
{
|
||||
return self::refresh(true);
|
||||
}
|
||||
elseif ($must_resend_keys)
|
||||
{
|
||||
return self::_setKeys();
|
||||
}
|
||||
else
|
||||
{
|
||||
$_SESSION['is_new_session'] = false;
|
||||
|
|
@ -431,6 +371,7 @@ class Session
|
|||
$_SESSION['RHYMIX']['language'] = \Context::getLangType();
|
||||
$_SESSION['RHYMIX']['timezone'] = DateTime::getTimezoneForCurrentUser();
|
||||
$_SESSION['RHYMIX']['secret'] = Security::getRandom(32, 'alnum');
|
||||
$_SESSION['RHYMIX']['domains'] = array();
|
||||
$_SESSION['RHYMIX']['tokens'] = array();
|
||||
$_SESSION['RHYMIX']['token'] = false;
|
||||
$_SESSION['is_webview'] = self::_isBuggyUserAgent();
|
||||
|
|
@ -450,6 +391,7 @@ class Session
|
|||
}
|
||||
|
||||
// Try autologin.
|
||||
self::$_autologin_key = self::_getAutologinKey();
|
||||
if (!$member_srl && self::$_autologin_key)
|
||||
{
|
||||
$member_srl = \MemberController::getInstance()->doAutologin(self::$_autologin_key);
|
||||
|
|
@ -464,7 +406,7 @@ class Session
|
|||
}
|
||||
}
|
||||
|
||||
// Pass control to refresh() to generate security keys.
|
||||
// Pass control to refresh() to generate domain information.
|
||||
return self::refresh();
|
||||
}
|
||||
|
||||
|
|
@ -474,47 +416,41 @@ class Session
|
|||
* This method can be used to invalidate old session cookies.
|
||||
* It is called automatically when someone logs in or out.
|
||||
*
|
||||
* @param bool $set_session_cookie
|
||||
* @param bool $refresh_cookie
|
||||
* @return bool
|
||||
*/
|
||||
public static function refresh($set_session_cookie = false)
|
||||
public static function refresh($refresh_cookie = false)
|
||||
{
|
||||
// Get session parameters.
|
||||
$domain = self::getDomain() ?: preg_replace('/:\\d+$/', '', strtolower($_SERVER['HTTP_HOST'] ?? ''));
|
||||
list($lifetime, $refresh_interval, $domain, $path, $secure, $samesite) = self::_getParams();
|
||||
$lifetime = $lifetime ? ($lifetime + time()) : 0;
|
||||
$options = array(
|
||||
'expires' => $lifetime,
|
||||
'path' => $path,
|
||||
'domain' => $domain,
|
||||
'secure' => $secure,
|
||||
'httponly' => true,
|
||||
'samesite' => $samesite,
|
||||
);
|
||||
|
||||
// Set the domain initialization timestamp.
|
||||
if (!isset($_SESSION['RHYMIX']['keys'][$domain]['started']))
|
||||
if (!isset($_SESSION['RHYMIX']['domains'][$domain]['started']))
|
||||
{
|
||||
$_SESSION['RHYMIX']['keys'][$domain]['started'] = time();
|
||||
$_SESSION['RHYMIX']['domains'][$domain]['started'] = time();
|
||||
}
|
||||
|
||||
// Reset the trusted information.
|
||||
if (!isset($_SESSION['RHYMIX']['keys'][$domain]['trusted']))
|
||||
if (!isset($_SESSION['RHYMIX']['domains'][$domain]['trusted']))
|
||||
{
|
||||
$_SESSION['RHYMIX']['keys'][$domain]['trusted'] = 0;
|
||||
$_SESSION['RHYMIX']['domains'][$domain]['trusted'] = 0;
|
||||
}
|
||||
|
||||
// Create or refresh the HTTP-only key.
|
||||
if (isset($_SESSION['RHYMIX']['keys'][$domain]['key1']))
|
||||
// Refresh the main session cookie.
|
||||
if ($refresh_cookie)
|
||||
{
|
||||
$_SESSION['RHYMIX']['keys'][$domain]['key1_prev'] = $_SESSION['RHYMIX']['keys'][$domain]['key1'];
|
||||
self::_setCookie(session_name(), session_id(), $options);
|
||||
self::destroyCookiesFromConflictingDomains(array(session_name()));
|
||||
}
|
||||
$_SESSION['RHYMIX']['keys'][$domain]['key1'] = Security::getRandom(24, 'alnum');
|
||||
$_SESSION['RHYMIX']['keys'][$domain]['key1_time'] = time();
|
||||
|
||||
// Create or refresh the HTTPS-only key.
|
||||
if (\RX_SSL)
|
||||
{
|
||||
if (isset($_SESSION['RHYMIX']['keys'][$domain]['key2']))
|
||||
{
|
||||
$_SESSION['RHYMIX']['keys'][$domain]['key2_prev'] = $_SESSION['RHYMIX']['keys'][$domain]['key2'];
|
||||
}
|
||||
$_SESSION['RHYMIX']['keys'][$domain]['key2'] = Security::getRandom(24, 'alnum');
|
||||
$_SESSION['RHYMIX']['keys'][$domain]['key2_time'] = time();
|
||||
}
|
||||
|
||||
// Pass control to _setKeys() to send the keys to the client.
|
||||
return self::_setKeys($set_session_cookie);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -554,7 +490,6 @@ class Session
|
|||
list($lifetime, $refresh_interval, $domain, $path, $secure, $samesite) = self::_getParams();
|
||||
|
||||
// Delete all cookies.
|
||||
self::_setKeys();
|
||||
self::destroyAutologinKeys();
|
||||
self::_unsetCookie(session_name(), $path, $domain);
|
||||
self::_unsetCookie('xe_logged', $path, $domain);
|
||||
|
|
@ -611,7 +546,7 @@ class Session
|
|||
if ($refresh)
|
||||
{
|
||||
self::checkLoginStatusCookie();
|
||||
return self::refresh();
|
||||
return self::refresh(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -685,7 +620,7 @@ class Session
|
|||
$domain = self::getDomain() ?: preg_replace('/:\\d+$/', '', strtolower($_SERVER['HTTP_HOST']));
|
||||
|
||||
// Check the 'trusted' parameter.
|
||||
if ($_SESSION['RHYMIX']['keys'][$domain]['trusted'] > time())
|
||||
if ($_SESSION['RHYMIX']['domains'][$domain]['trusted'] > time())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
|
@ -887,9 +822,9 @@ class Session
|
|||
$domain = self::getDomain() ?: preg_replace('/:\\d+$/', '', strtolower($_SERVER['HTTP_HOST']));
|
||||
|
||||
// Update the 'trusted' parameter if the current user is logged in.
|
||||
if (isset($_SESSION['RHYMIX']['keys'][$domain]) && $_SESSION['RHYMIX']['login'])
|
||||
if (isset($_SESSION['RHYMIX']['domains'][$domain]) && $_SESSION['RHYMIX']['login'])
|
||||
{
|
||||
$_SESSION['RHYMIX']['keys'][$domain]['trusted'] = time() + $duration;
|
||||
$_SESSION['RHYMIX']['domains'][$domain]['trusted'] = time() + $duration;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
|
|
@ -1132,86 +1067,21 @@ class Session
|
|||
}
|
||||
|
||||
/**
|
||||
* Get session keys.
|
||||
* Get the autologin key from the rx_autologin cookie.
|
||||
*
|
||||
* @return array
|
||||
* @return string|null
|
||||
*/
|
||||
protected static function _getKeys()
|
||||
protected static function _getAutologinKey()
|
||||
{
|
||||
// Initialize keys.
|
||||
$key1 = $key2 = $key3 = null;
|
||||
|
||||
// Fetch and validate the HTTP-only key.
|
||||
if (isset($_COOKIE['rx_sesskey1']) && ctype_alnum($_COOKIE['rx_sesskey1']) && strlen($_COOKIE['rx_sesskey1']) === 24)
|
||||
{
|
||||
$key1 = $_COOKIE['rx_sesskey1'];
|
||||
}
|
||||
|
||||
// Fetch and validate the HTTPS-only key.
|
||||
if (isset($_COOKIE['rx_sesskey2']) && ctype_alnum($_COOKIE['rx_sesskey2']) && strlen($_COOKIE['rx_sesskey2']) === 24)
|
||||
{
|
||||
$key2 = $_COOKIE['rx_sesskey2'];
|
||||
}
|
||||
|
||||
// Fetch and validate the autologin key.
|
||||
if (isset($_COOKIE['rx_autologin']) && ctype_alnum($_COOKIE['rx_autologin']) && strlen($_COOKIE['rx_autologin']) === 48)
|
||||
{
|
||||
$key3 = $_COOKIE['rx_autologin'];
|
||||
}
|
||||
|
||||
return array($key1, $key1 === null ? null : $key2, $key3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set session keys.
|
||||
*
|
||||
* @param bool $set_session_cookie
|
||||
* @return bool
|
||||
*/
|
||||
protected static function _setKeys($set_session_cookie = false)
|
||||
{
|
||||
// Get session parameters.
|
||||
list($lifetime, $refresh_interval, $domain, $path, $secure, $samesite) = self::_getParams();
|
||||
$alt_domain = $domain ?: preg_replace('/:\\d+$/', '', strtolower($_SERVER['HTTP_HOST'] ?? ''));
|
||||
$lifetime = $lifetime ? ($lifetime + time()) : 0;
|
||||
$options = array(
|
||||
'expires' => $lifetime,
|
||||
'path' => $path,
|
||||
'domain' => $domain,
|
||||
'secure' => $secure,
|
||||
'httponly' => true,
|
||||
'samesite' => $samesite,
|
||||
);
|
||||
|
||||
// Refresh the main session cookie.
|
||||
if ($set_session_cookie)
|
||||
{
|
||||
self::_setCookie(session_name(), session_id(), $options);
|
||||
}
|
||||
|
||||
// Set or destroy the HTTP-only key.
|
||||
if (isset($_SESSION['RHYMIX']['keys'][$alt_domain]['key1']))
|
||||
{
|
||||
self::_setCookie('rx_sesskey1', $_SESSION['RHYMIX']['keys'][$alt_domain]['key1'], $options);
|
||||
$_COOKIE['rx_sesskey1'] = $_SESSION['RHYMIX']['keys'][$alt_domain]['key1'];
|
||||
return $_COOKIE['rx_autologin'];
|
||||
}
|
||||
else
|
||||
{
|
||||
self::_unsetCookie('rx_sesskey1', $path, $domain);
|
||||
unset($_COOKIE['rx_sesskey1']);
|
||||
return null;
|
||||
}
|
||||
|
||||
// Set the HTTPS-only key.
|
||||
if (\RX_SSL && isset($_SESSION['RHYMIX']['keys'][$alt_domain]['key2']))
|
||||
{
|
||||
$options['secure'] = true;
|
||||
self::_setCookie('rx_sesskey2', $_SESSION['RHYMIX']['keys'][$alt_domain]['key2'], $options);
|
||||
$_COOKIE['rx_sesskey2'] = $_SESSION['RHYMIX']['keys'][$alt_domain]['key2'];
|
||||
}
|
||||
|
||||
// Delete conflicting domain cookies.
|
||||
self::destroyCookiesFromConflictingDomains(array(session_name(), 'rx_autologin', 'rx_login_status', 'rx_sesskey1', 'rx_sesskey2'));
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1227,7 +1097,7 @@ class Session
|
|||
$name = strval($name);
|
||||
$value = strval($value);
|
||||
|
||||
if (version_compare(PHP_VERSION, '7.3', '>='))
|
||||
if (PHP_VERSION_ID >= 70300)
|
||||
{
|
||||
$result = setcookie($name, $value, $options);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue