Skip to content

Commit 4111a74

Browse files
feat: Harden login captcha gate by replacing request-body counter with server-side session counter (UserController::postLogin)
1 parent c517b7c commit 4111a74

4 files changed

Lines changed: 240 additions & 76 deletions

File tree

app/Http/Controllers/UserController.php

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -396,8 +396,8 @@ public function postLogin()
396396
{
397397
$max_login_attempts_2_show_captcha = $this->server_configuration_service->getConfigValue("MaxFailed.LoginAttempts.2ShowCaptcha");
398398
$max_login_failed_attempts = intval($this->server_configuration_service->getConfigValue("MaxFailed.Login.Attempts"));
399-
$login_attempts = 0;
400-
$username = '';
399+
$login_attempts = (int) Session::get('captcha_failed_attempts', 0);
400+
$username = '';
401401
$user = null;
402402

403403
try
@@ -411,7 +411,6 @@ public function postLogin()
411411
if (isset($data['password']))
412412
$data['password'] = trim($data['password']);
413413

414-
$login_attempts = intval(Request::input('login_attempts'));
415414
// Build the validation constraint set.
416415
$rules = [
417416
'username' => 'required|email',
@@ -436,7 +435,10 @@ public function postLogin()
436435
$connection = $data['connection'] ?? null;
437436

438437
try {
438+
$user = $this->auth_service->getUserByUsername($username);
439439
if ($flow == "password" && $this->auth_service->login($username, $password, $remember)) {
440+
Session::forget('captcha_failed_attempts');
441+
Session::save();
440442
return $this->login_strategy->postLogin();
441443
}
442444

@@ -468,15 +470,18 @@ public function postLogin()
468470

469471
$otpClaim = OAuth2OTP::fromParams($username, $connection, $password);
470472
$this->auth_service->loginWithOTP($otpClaim, $client);
473+
Session::forget('captcha_failed_attempts');
474+
Session::save();
471475
return $this->login_strategy->postLogin();
472476
}
473477
} catch (AuthenticationException $ex) {
474478
// failed login attempt...
475479

476-
$user = $this->auth_service->getUserByUsername($username);
477-
if (!is_null($user)) {
478-
$login_attempts = $user->getLoginFailedAttempt();
479-
}
480+
$login_attempts = $login_attempts + 1;
481+
Session::put('captcha_failed_attempts', $login_attempts);
482+
Session::save();
483+
484+
// User.loginFailedAttempt drives account lockout (persisted by auth_service).
480485

481486
return $this->login_strategy->errorLogin
482487
(
@@ -525,6 +530,9 @@ public function postLogin()
525530
Log::warning($ex1);
526531

527532
$user = $this->auth_service->getUserByUsername($username);
533+
$login_attempts = $login_attempts + 1;
534+
Session::put('captcha_failed_attempts', $login_attempts);
535+
Session::save();
528536

529537
$response_data = [
530538
'max_login_attempts_2_show_captcha' => $max_login_attempts_2_show_captcha,

resources/js/login/login.js

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -185,7 +185,6 @@ const PasswordInputForm = ({
185185
<input type="hidden" value={userNameValue} id="username" name="username"/>
186186
<input type="hidden" value={csrfToken} id="_token" name="_token"/>
187187
<input type="hidden" value="password" id="flow" name="flow"/>
188-
<input type="hidden" value={loginAttempts} id="login_attempts" name="login_attempts"/>
189188
{shouldShowCaptcha() && captchaPublicKey &&
190189
<Turnstile
191190
className={styles.turnstile}
@@ -271,7 +270,6 @@ const OTPInputForm = ({
271270
<input type="hidden" value="otp" id="flow" name="flow"/>
272271
<input type="hidden" value={otpCode} id="password" name="password"/>
273272
<input type="hidden" value="email" id="connection" name="connection"/>
274-
<input type="hidden" value={loginAttempts} id="login_attempts" name="login_attempts"/>
275273
{shouldShowCaptcha() && captchaPublicKey &&
276274
<Turnstile
277275
className={styles.turnstile}

resources/views/auth/login.blade.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@
6262
config.maxLoginFailedAttempts = {{Session::get("max_login_failed_attempts")}};
6363
@endif
6464
65-
@if(Session::has('login_attempts'))
66-
config.loginAttempts = {{Session::get("login_attempts")}};
65+
@if(Session::has('captcha_failed_attempts'))
66+
config.loginAttempts = {{Session::get("captcha_failed_attempts")}};
6767
@endif
6868
6969
@if(Session::has('user_is_active'))

0 commit comments

Comments
 (0)