Skip to content

Commit 17d8ac6

Browse files
committed
Add rate limiting to login, register, forgot-password and TOTP
1 parent 983afd7 commit 17d8ac6

2 files changed

Lines changed: 12 additions & 6 deletions

File tree

app/Http/Controllers/TwoFactorController.php

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ public function submit(Request $request)
5959
throw ValidationException::withMessages(['code' => 'Invalid Yubikey code.']);
6060
}
6161
} elseif ($data['method'] === 'totp') {
62-
if (! $this->verifyTOTP($data, $twoFactors)) {
62+
if (! $this->verifyTOTP($data, $twoFactors, $user)) {
6363
throw ValidationException::withMessages(['code' => 'Invalid TOTP code.']);
6464
}
6565
} else {
@@ -96,12 +96,18 @@ public function verifyYubikey($data, Collection $twoFactors, $user): bool
9696
return $success;
9797
}
9898

99-
public function verifyTOTP($data, Collection $twoFactors): bool
99+
public function verifyTOTP($data, Collection $twoFactors, $user): bool
100100
{
101+
$limitKey = 'totp-verify-' . $user->id;
102+
if (RateLimiter::tooManyAttempts($limitKey, 10)) {
103+
throw ValidationException::withMessages(['code' => 'Too many attempts. Please try again later.']);
104+
}
105+
RateLimiter::hit($limitKey, 120);
106+
101107
$factorModel = $twoFactors->first();
102108
$success = (new TwoFactorAuth())->verifyCode($factorModel->secret, $data['code']);
103109
if ($success) {
104-
// Update last used at
110+
RateLimiter::clear($limitKey);
105111
$factorModel->update(['last_used_at' => now()]);
106112
}
107113

routes/web.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
'login.view'
1919
);
2020
Route::post('login', [LoginController::class, 'submit'])
21-
->middleware([HandlePrecognitiveRequests::class])
21+
->middleware([HandlePrecognitiveRequests::class, 'throttle:5,1'])
2222
->name('login.submit');
2323

2424
Route::get('two-factor',
@@ -39,12 +39,12 @@
3939
// Register
4040
Route::inertia('register', 'Auth/Register')->name('register.view');
4141
Route::post('register', RegisterController::class)
42-
->middleware(['guest', HandlePrecognitiveRequests::class])
42+
->middleware(['guest', HandlePrecognitiveRequests::class, 'throttle:5,1'])
4343
->name('register.store');
4444
// Password Reset
4545
Route::inertia('forgot-password', 'Auth/ForgotPassword')->name('forgot-password.view');
4646
Route::post('forgot-password', ForgotPasswordController::class)
47-
->middleware([HandlePrecognitiveRequests::class])
47+
->middleware([HandlePrecognitiveRequests::class, 'throttle:5,1'])
4848
->name('forgot-password.store');
4949
// Set new Password
5050
Route::get('password-reset', [PasswordResetController::class, 'view'])->name('password-reset.view');

0 commit comments

Comments
 (0)