mirror of
https://github.com/delight-im/PHP-Auth.git
synced 2025-08-05 15:47:25 +02:00
Improve cookie handling to fix domain issues and add same-site flag
This commit is contained in:
@@ -254,8 +254,13 @@ $uuid = \Delight\Auth\Auth::createUuid();
|
|||||||
* logout
|
* logout
|
||||||
* full and reliable destruction of session
|
* full and reliable destruction of session
|
||||||
* session management
|
* session management
|
||||||
* protection against session hijacking
|
* protection against session hijacking via cross-site scripting (XSS)
|
||||||
|
* do *not* permit script-based access to cookies
|
||||||
|
* restrict cookies to HTTPS to prevent session hijacking via non-secure HTTP
|
||||||
* protection against session fixation attacks
|
* protection against session fixation attacks
|
||||||
|
* protection against cross-site request forgery (CSRF)
|
||||||
|
* works automatically (i.e. no need for CSRF tokens everywhere)
|
||||||
|
* do *not* use HTTP `GET` requests for "dangerous" operations
|
||||||
* throttling
|
* throttling
|
||||||
* per IP address
|
* per IP address
|
||||||
* per account
|
* per account
|
||||||
|
67
src/Auth.php
67
src/Auth.php
@@ -85,7 +85,7 @@ class Auth {
|
|||||||
session_set_cookie_params($params['lifetime'], $params['path'], $params['domain'], $params['secure'], $params['httponly']);
|
session_set_cookie_params($params['lifetime'], $params['path'], $params['domain'], $params['secure'], $params['httponly']);
|
||||||
|
|
||||||
// start the session
|
// start the session
|
||||||
@session_start();
|
@\Delight\Cookie\Session::start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Improves the application's security over HTTP(S) by setting specific headers */
|
/** Improves the application's security over HTTP(S) by setting specific headers */
|
||||||
@@ -388,7 +388,18 @@ class Auth {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set the cookie with the selector and token
|
// set the cookie with the selector and token
|
||||||
$result = setcookie(self::COOKIE_NAME_REMEMBER, $content, $expires, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
|
$cookie = new \Delight\Cookie\Cookie(self::COOKIE_NAME_REMEMBER);
|
||||||
|
$cookie->setValue($content);
|
||||||
|
$cookie->setExpiryTime($expires);
|
||||||
|
if (!empty($params['path'])) {
|
||||||
|
$cookie->setPath($params['path']);
|
||||||
|
}
|
||||||
|
if (!empty($params['domain'])) {
|
||||||
|
$cookie->setDomain($params['domain']);
|
||||||
|
}
|
||||||
|
$cookie->setHttpOnly($params['httponly']);
|
||||||
|
$cookie->setSecureOnly($params['secure']);
|
||||||
|
$result = $cookie->save();
|
||||||
|
|
||||||
if ($result === false) {
|
if ($result === false) {
|
||||||
throw new HeadersAlreadySentError();
|
throw new HeadersAlreadySentError();
|
||||||
@@ -410,7 +421,7 @@ class Auth {
|
|||||||
$stmt->execute();
|
$stmt->execute();
|
||||||
|
|
||||||
// re-generate the session ID to prevent session fixation attacks
|
// re-generate the session ID to prevent session fixation attacks
|
||||||
session_regenerate_id(true);
|
\Delight\Cookie\Session::regenerate(true);
|
||||||
|
|
||||||
// save the user data in the session
|
// save the user data in the session
|
||||||
$this->setLoggedIn(true);
|
$this->setLoggedIn(true);
|
||||||
@@ -456,8 +467,17 @@ class Auth {
|
|||||||
// get our cookie settings
|
// get our cookie settings
|
||||||
$params = $this->createCookieSettings();
|
$params = $this->createCookieSettings();
|
||||||
|
|
||||||
// set the cookie with the selector and token
|
// cause the session cookie to be deleted
|
||||||
$result = setcookie(session_name(), '', time() - 3600, $params['path'], $params['domain'], $params['secure'], $params['httponly']);
|
$cookie = new \Delight\Cookie\Cookie(session_name());
|
||||||
|
if (!empty($params['path'])) {
|
||||||
|
$cookie->setPath($params['path']);
|
||||||
|
}
|
||||||
|
if (!empty($params['domain'])) {
|
||||||
|
$cookie->setDomain($params['domain']);
|
||||||
|
}
|
||||||
|
$cookie->setHttpOnly($params['httponly']);
|
||||||
|
$cookie->setSecureOnly($params['secure']);
|
||||||
|
$result = $cookie->delete();
|
||||||
|
|
||||||
if ($result === false) {
|
if ($result === false) {
|
||||||
throw new HeadersAlreadySentError();
|
throw new HeadersAlreadySentError();
|
||||||
@@ -829,8 +849,6 @@ class Auth {
|
|||||||
// get the default cookie settings
|
// get the default cookie settings
|
||||||
$params = session_get_cookie_params();
|
$params = session_get_cookie_params();
|
||||||
|
|
||||||
// optimize the cookie domain
|
|
||||||
$params['domain'] = self::optimizeCookieDomain($params['domain']);
|
|
||||||
// check if we want to send cookies via SSL/TLS only
|
// check if we want to send cookies via SSL/TLS only
|
||||||
$params['secure'] = $params['secure'] || $this->useHttps;
|
$params['secure'] = $params['secure'] || $this->useHttps;
|
||||||
// check if we want to send cookies via HTTP(S) only
|
// check if we want to send cookies via HTTP(S) only
|
||||||
@@ -840,41 +858,6 @@ class Auth {
|
|||||||
return $params;
|
return $params;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Optimizes the specified cookie domain
|
|
||||||
*
|
|
||||||
* @param string $domain the supplied cookie domain
|
|
||||||
* @return string the optimized cookie domain
|
|
||||||
*/
|
|
||||||
private static function optimizeCookieDomain($domain) {
|
|
||||||
// if no domain has been explicitly provided
|
|
||||||
if (empty($domain)) {
|
|
||||||
// use the current hostname as a default
|
|
||||||
$domain = $_SERVER['SERVER_NAME'];
|
|
||||||
}
|
|
||||||
|
|
||||||
// if the domain name starts with the `www` subdomain
|
|
||||||
if (substr($domain, 0, 4) === 'www.') {
|
|
||||||
// strip the subdomain
|
|
||||||
$domain = substr($domain, 4);
|
|
||||||
}
|
|
||||||
|
|
||||||
// count the dots in the domain name
|
|
||||||
$numDots = substr_count($domain, '.');
|
|
||||||
|
|
||||||
// if there is no dot at all (usually `localhost`) or only a single dot (no subdomain)
|
|
||||||
if ($numDots < 2) {
|
|
||||||
// if the domain doesn't already start with a dot
|
|
||||||
if (substr($domain, 0, 1) !== '.') {
|
|
||||||
// prepend a dot to allow all subdomains
|
|
||||||
$domain = '.'.$domain;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// return the optimized domain name
|
|
||||||
return $domain;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a random string with the given maximum length
|
* Creates a random string with the given maximum length
|
||||||
*
|
*
|
||||||
|
Reference in New Issue
Block a user