diff --git a/application/config/config-defaults.php b/application/config/config-defaults.php index 6db1d4b5f88..6b7db2b6ec3 100644 --- a/application/config/config-defaults.php +++ b/application/config/config-defaults.php @@ -315,6 +315,13 @@ */ $config['showrelevance'] = false; +/** +* To prevent brute force against forgotten password functionality, there is a random delay +* that prevent attacker from knowing whether username and email address are valid or not. +*/ +$config['minforgottenpasswordemaildelay'] = 500000; +$config['maxforgottenpasswordemaildelay'] = 1500000; + /** * PDF Export Settings * This feature configures PDF export for Export Answers diff --git a/application/controllers/admin/authentication.php b/application/controllers/admin/authentication.php index 26d2163249a..37bef6e26d1 100644 --- a/application/controllers/admin/authentication.php +++ b/application/controllers/admin/authentication.php @@ -145,18 +145,19 @@ public function forgotpassword() $aFields = User::model()->findAllByAttributes(array('users_name' => $sUserName, 'email' => $sEmailAddr)); + // Preventing attacker from easily knowing whether the user and email address are valid or not (and slowing down brute force attacks) + usleep(rand(Yii::app()->getConfig("minforgottenpasswordemaildelay"),Yii::app()->getConfig("maxforgottenpasswordemaildelay"))); + if (count($aFields) < 1) { - // wrong or unknown username and/or email - $aData['errormsg'] = gT('User name and/or email not found!'); - $aData['maxattempts'] = ''; - $this->_renderWrappedTemplate('authentication', 'error', $aData); + // Wrong or unknown username and/or email. For security reasons, we don't show a fail message + $aData['message'] = '
'.gT('If username and email that you specified are valid, a new password has been sent to you').'
'; } else { - $aData['message'] = $this->_sendPasswordEmail($sEmailAddr, $aFields); - $this->_renderWrappedTemplate('authentication', 'message', $aData); + $aData['message'] = '
'.$this->_sendPasswordEmail($sEmailAddr, $aFields).'
'; } + $this->_renderWrappedTemplate('authentication', 'message', $aData); } } @@ -188,12 +189,12 @@ private function _sendPasswordEmail($sEmailAddr, $aFields) if (SendEmailMessage($body, $sSubject, $sTo, $sFrom, $sSiteName, false, $sSiteAdminBounce)) { User::model()->updatePassword($aFields[0]['uid'], $sNewPass); - $sMessage = $username . '
' . $email . '

' . gT('An email with your login data was sent to you.'); + // For security reasons, we don't show a successful message + $sMessage = gT('If username and email that you specified are valid, a new password has been sent to you'); } else { - $sTmp = str_replace("{NAME}", '' . $aFields[0]['users_name'] . '', gT("Email to {NAME} ({EMAIL}) failed.")); - $sMessage = str_replace("{EMAIL}", $sEmailAddr, $sTmp) . '
'; + $sMessage = gT('Email failed'); } return $sMessage;