Enhance rate limit for sending password reset email

This commit is contained in:
Pig Fang 2018-08-17 16:07:24 +08:00
parent 0ef92a5565
commit 939d71923b
4 changed files with 26 additions and 9 deletions

View File

@ -152,8 +152,18 @@ class AuthController extends Controller
return json(trans('auth.forgot.disabled'), 1);
}
if (Session::has('last_mail_time') && (time() - session('last_mail_time')) < 60)
return json(trans('auth.forgot.frequent-mail'), 1);
$rateLimit = 180;
$lastMailCacheKey = sha1('last_mail_'.Utils::getClientIp());
$remain = $rateLimit + Cache::get($lastMailCacheKey, 0) - time();
// Rate limit
if ($remain > 0) {
return json([
'errno' => 2,
'msg' => trans('auth.forgot.frequent-mail'),
'remain' => $remain
]);
}
// Get user instance
$user = $users->get($request->input('email'), 'email');
@ -171,7 +181,7 @@ class AuthController extends Controller
return json(trans('auth.forgot.failed', ['msg' => $e->getMessage()]), 2);
}
Session::put('last_mail_time', time());
Cache::put($lastMailCacheKey, time(), 60);
return json(trans('auth.forgot.success'), 0);
}

View File

@ -28,7 +28,7 @@ forgot:
message: We will send you an E-mail to verify.
login-link: I do remember it
disabled: Password resetting is not available.
frequent-mail: You click the send button too fast. Wait for 60 secs, guy.
frequent-mail: You click the send button too fast. Wait for some minutes, guy.
unregistered: The email address is not registered.
success: Mail is sent. Will be expired in 1 hour, please check.
failed: Fail to send mail, detailed message :msg

View File

@ -28,7 +28,7 @@ forgot:
message: 我们将会向您发送一封验证邮件
login-link: 我又想起来了
disabled: 本站已关闭重置密码功能
frequent-mail: 你邮件发送得太频繁啦,过 60 秒后再点发送吧
frequent-mail: 你邮件发送得太频繁啦,过会儿再点发送吧
unregistered: 该邮箱尚未注册
success: 邮件已发送,一小时内有效,请注意查收。
failed: 邮件发送失败,详细信息::msg

View File

@ -394,16 +394,21 @@ class AuthControllerTest extends TestCase
]);
config(['mail.driver' => 'smtp']);
$lastMailCacheKey = sha1('last_mail_'.Utils::getClientIp());
// Should be forbidden if sending email frequently
$this->withSession(['last_mail_time' => time()])->postJson('/auth/forgot', [
$this->withCache([
$lastMailCacheKey => time()
])->postJson('/auth/forgot', [
'captcha' => 'a'
])->assertJson([
'errno' => 1,
'errno' => 2,
'msg' => trans('auth.forgot.frequent-mail')
]);
$this->flushCache();
$this->flushSession();
// Should return a warning if user is not existed
$this->flushSession();
$user = factory(User::class)->create();
$this->withSession(['phrase' => 'a'])->postJson('/auth/forgot', [
'email' => 'nope@nope.net',
@ -419,7 +424,9 @@ class AuthControllerTest extends TestCase
])->assertJson([
'errno' => 0,
'msg' => trans('auth.forgot.success')
])->assertSessionHas('last_mail_time');
]);
$this->assertCacheHas($lastMailCacheKey);
$this->flushCache();
Mail::assertSent(ForgotPassword::class, function ($mail) use ($user) {
return $mail->hasTo($user->email);
});