[SS-2017-005] User enumeration via timing attack mitigated

This commit is contained in:
Daniel Hensby 2017-09-04 17:11:02 +01:00
parent c0003bca3d
commit f0262a8fd9
No known key found for this signature in database
GPG Key ID: B00D1E9767F0B06E
3 changed files with 29 additions and 5 deletions

View File

@ -18,9 +18,18 @@ abstract class LoginForm extends Form {
* form.
* @var string
*/
protected $authenticator_class;
/**
* The minimum amount of time authenticating is allowed to take in milliseconds.
*
* Protects against timing enumeration attacks
*
* @config
* @var int
*/
private static $min_auth_time = 350;
/**
* Get the authenticator instance
*

View File

@ -150,6 +150,10 @@ class MemberAuthenticator extends Authenticator {
* @see Security::setDefaultAdmin()
*/
public static function authenticate($data, Form $form = null) {
// minimum execution time for authenticating a member
$minExecTime = LoginForm::config()->min_auth_time / 1000;
$startTime = microtime(true);
// Find authenticated member
$member = static::authenticate_member($data, $form, $success);
@ -170,6 +174,11 @@ class MemberAuthenticator extends Authenticator {
if($success) Session::clear('BackURL');
$waitFor = $minExecTime - (microtime(true) - $startTime);
if ($waitFor > 0) {
usleep($waitFor * 1000000);
}
return $success ? $member : null;
}

View File

@ -294,6 +294,10 @@ JS;
* @param array $data Submitted data
*/
public function forgotPassword($data) {
// minimum execution time for authenticating a member
$minExecTime = self::config()->min_auth_time / 1000;
$startTime = microtime(true);
// Ensure password is given
if(empty($data['Email'])) {
$this->sessionMessage(
@ -311,10 +315,8 @@ JS;
// Allow vetoing forgot password requests
$results = $this->extend('forgotPassword', $member);
if($results && is_array($results) && in_array(false, $results, true)) {
return $this->controller->redirect('Security/lostpassword');
}
if($member) {
$this->controller->redirect('Security/lostpassword');
} elseif ($member) {
$token = $member->generateAutologinTokenAndStoreHash();
$e = Member_ForgotPasswordEmail::create();
@ -338,6 +340,10 @@ JS;
$this->controller->redirect('Security/lostpassword');
}
$waitFor = $minExecTime - (microtime(true) - $startTime);
if ($waitFor > 0) {
usleep($waitFor * 1000000);
}
}
}