case 4726 - login lockout per login name and per address

Failed logins are counted in memory (util/LoginThrottle.cs): 10 per login
name or 50 per client address within 15 minutes, then attempts are refused
with 429 for the rest of the window without checking the password. A
correct password clears the login's count; loopback is not counted per
address. Each lockout is logged. F6 fixed (2FA part in case 4710).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-24 20:12:26 -07:00
parent 80f81aea0f
commit d8be701bcd
5 changed files with 100 additions and 3 deletions

View File

@@ -214,7 +214,7 @@ take the next free number; a fixed or accepted finding keeps its ID and changes
| F31 | Medium | **fixed in case 4724** | The SMTP password is returned to read-only roles (OpsAdminRestricted, BizAdmin, BizAdminRestricted) |
| F32 | Medium | confirmed (code) | A real-looking SMTP account and password are in the DEBUG defaults in `raven` and `sockeye` source |
| F34 | Medium | **fixed in case 4722** | Shipped client libraries behind on security fixes: DOMPurify 2.3.8 (wiki sanitiser), Vuetify 2.6.6 |
| F6 | Medium | confirmed | No lockout or rate limit on login or the 2FA step; no password rules |
| F6 | Medium | **fixed in cases 4710 and 4726** | No lockout or rate limit on login or the 2FA step; no password rules |
| F9 | Medium | **fixed in case 4725** | Default SuperUser password (by design for trials), and an anonymous route that says whether it is still set |
| F36 | Low | confirmed (code) | AyaNova listens on all interfaces on plain HTTP port 7575 in every template; hosted droplets are protected by a cloud firewall |
| F37 | Low | accepted (John) | Standalone PostgreSQL accepts any local connection without a password (`trust`) |
@@ -306,6 +306,8 @@ per-user or per-address lockout, and parallel requests are not slowed. Hosted ng
as password). Fix options: count failures per login and per temp token with a short lockout;
`limit_req` on `/api/v8/auth` in the hosted nginx template.
**Fixed (2026-10-24).** 2FA: case 4710 (5 wrong codes clear the temporary token). Password login: case 4726, `util/LoginThrottle.cs` in AyaNova and Sockeye (Sockeye's login is public too; only SSH to its droplet is limited to the office address). Failures are counted in memory: 10 per login name or 50 per client address within 15 minutes, then attempts are refused with 429 "Too many failed login attempts" for the rest of the window, without checking the password; a correct password clears the login's count; unknown logins are counted the same way. Loopback is not counted per address (the hosted nginx and IIS pass the real client address through the forwarded headers, which are trusted from loopback only). Each lockout is logged as a warning. Accepted: an attacker can keep a known login locked by failing 10 times every 15 minutes. Proved in both servers, the per-address limit through `X-Forwarded-For` with a documentation address; test `LoginLockout`. The password rule and nginx `limit_req` are in Deferred in `NET10-PORT.md`.
### F7 Password change does not end sessions; download key loses its expiry (pass 2)
`UserBiz.ChangePasswordAsync` (used by change-password and reset-password) does not replace