mirror of
https://github.com/Ark0N/Codeman.git
synced 2026-11-14 02:29:33 +01:00
fix(auth): keep the single-user login throttle at 10, widen only the multi-user pre-gate
Single-user mode has no per-username bucket, so its per-IP bucket is the only limit on guesses against the one password, and behind a tunnel every client shares 127.0.0.1. Put it back on AUTH_FAILURE_MAX (10). AUTH_IP_FAILURE_MAX (50) now gates only the multi-user per-IP pre-gate, which runs before the scrypt verify and so refuses even a correct password; the per-username bucket still caps each account at 10. Move the headroom test out of the single-user suite and add a multi-user test that sprays wrong passwords across usernames (9 each) and expects 401 for the first 50, then 429 for the 51st and for a correct password. Update the docs that still described 10 per IP for every mode, and resync the plugin mirror of the codeman skill.
This commit is contained in:
1 parent
ebb9e00de9
commit
175e3b8320
12 files changed
+61
-35
No files matched your search
@@ -23,15 +23,17 @@ export const MAX_AUTH_SESSIONS = 100;
|
||||
|
||||
/**
|
||||
* Max failed auth attempts per bucket before 429 rejection. Applies to the
|
||||
* per-username lockout and the hook-secret bucket.
|
||||
* single-user per-IP bucket, the multi-user per-username lockout and the
|
||||
* hook-secret bucket.
|
||||
*/
|
||||
export const AUTH_FAILURE_MAX = 10;
|
||||
|
||||
/**
|
||||
* Max failed login attempts per client IP before 429 rejection. Wider than
|
||||
* AUTH_FAILURE_MAX because one egress IP (NAT, a tunnel, an automated client) can
|
||||
* carry many users' or retries' failures; the per-username lockout above still
|
||||
* caps guesses against any one account.
|
||||
* Max failed login attempts per client IP for the multi-user pre-gate, which
|
||||
* runs before the scrypt verify and so refuses even a correct password once
|
||||
* reached. Wider than AUTH_FAILURE_MAX because one egress IP (NAT, a tunnel) can
|
||||
* carry many users' failures; the per-username bucket still caps guesses against
|
||||
* each account at AUTH_FAILURE_MAX. Single-user mode does not use this.
|
||||
*/
|
||||
export const AUTH_IP_FAILURE_MAX = 50;
|
||||
|
||||
|
||||
@@ -448,7 +448,7 @@ export function registerAuthMiddleware(app: FastifyInstance, https: boolean, bas
|
||||
|
||||
// Rate limit only requests that failed to authenticate on this attempt.
|
||||
const failures = authFailures.get(clientIp) ?? 0;
|
||||
if (failures >= AUTH_IP_FAILURE_MAX) {
|
||||
if (failures >= AUTH_FAILURE_MAX) {
|
||||
sendAuthRateLimit(reply, authFailures, clientIp);
|
||||
return;
|
||||
}
|
||||
@@ -572,7 +572,9 @@ function registerMultiUserAuthHook(
|
||||
|
||||
// 2. Basic Auth against the user store (scrypt verify).
|
||||
// Per-IP pre-gate bounds scrypt CPU cost from one source (does NOT gate on the
|
||||
// per-username bucket here; see below).
|
||||
// per-username bucket here; see below). Wider than AUTH_FAILURE_MAX: it refuses
|
||||
// even a correct password, so behind a shared egress IP (NAT, a tunnel) a narrow
|
||||
// cap would let a few wrong guesses lock everyone out.
|
||||
const ipFail = authFailures.get(clientIp) ?? 0;
|
||||
if (ipFail >= AUTH_IP_FAILURE_MAX) {
|
||||
sendAuthRateLimit(reply, authFailures, clientIp);
|
||||
|
||||
Reference in new issue
Block a user