NEW Option for secure "remember me" cookie

Fixes #8234
This commit is contained in:
Ingo Schommer 2018-07-13 11:08:47 +12:00 committed by Daniel Hensby
parent 14784f06d8
commit 114b0a5ea7
No known key found for this signature in database
GPG Key ID: D8DEBC4C8E7BC8B9
2 changed files with 53 additions and 10 deletions

View File

@ -705,6 +705,20 @@ SilverStripe\Control\Session:
cookie_secure: true
```
The same treatment should be applied to the cookie responsible for remembering logins across sessions:
```yml
---
Name: secure-alc
Except:
environment: dev
---
SilverStripe\Core\Injector\Injector:
SilverStripe\Security\MemberAuthenticator\CookieAuthenticationHandler:
properties:
TokenCookieSecure: true
```
For other cookies set by your application we should also ensure the users are provided with secure cookies by setting
the "Secure" and "HTTPOnly" flags. These flags prevent them from being stolen by an attacker through javascript.

View File

@ -27,6 +27,11 @@ class CookieAuthenticationHandler implements AuthenticationHandler
*/
private $tokenCookieName;
/**
* @var boolean
*/
private $tokenCookieSecure = false;
/**
* @var IdentityStore
*/
@ -76,6 +81,28 @@ class CookieAuthenticationHandler implements AuthenticationHandler
return $this;
}
/**
* Get the name of the cookie used to store an login token
*
* @return string
*/
public function getTokenCookieSecure()
{
return $this->tokenCookieSecure;
}
/**
* Set cookie with HTTPS only flag
*
* @param string $tokenCookieSecure
* @return $this
*/
public function setTokenCookieSecure($tokenCookieSecure)
{
$this->tokenCookieSecure = $tokenCookieSecure;
return $this;
}
/**
* Once a member is found by authenticateRequest() pass it to this identity store
*
@ -128,11 +155,11 @@ class CookieAuthenticationHandler implements AuthenticationHandler
/** @var RememberLoginHash $rememberLoginHash */
$rememberLoginHash = RememberLoginHash::get()
->filter(array(
->filter([
'MemberID' => $member->ID,
'DeviceID' => $deviceID,
'Hash' => $hash
))->first();
'Hash' => $hash,
])->first();
if (!$rememberLoginHash) {
return null;
}
@ -189,13 +216,14 @@ class CookieAuthenticationHandler implements AuthenticationHandler
$rememberLoginHash = RememberLoginHash::generate($member);
$tokenExpiryDays = RememberLoginHash::config()->uninherited('token_expiry_days');
$deviceExpiryDays = RememberLoginHash::config()->uninherited('device_expiry_days');
$secure = $this->getTokenCookieSecure();
Cookie::set(
$this->getTokenCookieName(),
$member->ID . ':' . $rememberLoginHash->getToken(),
$tokenExpiryDays,
null,
null,
null,
$secure,
true
);
Cookie::set(
@ -204,7 +232,7 @@ class CookieAuthenticationHandler implements AuthenticationHandler
$deviceExpiryDays,
null,
null,
null,
$secure,
true
);
} else {
@ -220,7 +248,7 @@ class CookieAuthenticationHandler implements AuthenticationHandler
{
$member = Security::getCurrentUser();
if ($member) {
RememberLoginHash::clear($member, Cookie::get('alc_device'));
RememberLoginHash::clear($member, Cookie::get($this->getDeviceCookieName()));
}
$this->clearCookies();
@ -236,9 +264,10 @@ class CookieAuthenticationHandler implements AuthenticationHandler
*/
protected function clearCookies()
{
Cookie::set($this->getTokenCookieName(), null);
Cookie::set($this->getDeviceCookieName(), null);
Cookie::force_expiry($this->getTokenCookieName());
Cookie::force_expiry($this->getDeviceCookieName());
$secure = $this->getTokenCookieSecure();
Cookie::set($this->getTokenCookieName(), null, null, null, null, $secure);
Cookie::set($this->getDeviceCookieName(), null, null, null, null, $secure);
Cookie::force_expiry($this->getTokenCookieName(), null, null, null, null, $secure);
Cookie::force_expiry($this->getDeviceCookieName(), null, null, null, null, $secure);
}
}