fix(P1): rate-limit auth endpoints — F7
Pre-audit: 20 rapid wrong-password attempts all returned 401 with no lockout. Brute-force open. Post-fix: better-auth's built-in rate limiter caps /sign-in/email at 5 attempts per 60s. Verified live — attempts 1-5 return 401, attempt 6+ returns 429 "Too many requests". Same tight cap applied to /sign-up/email, /forget-password, /reset-password. Default 120/min for everything else so legitimate multi-widget dashboards aren't hampered. Memory storage in this commit (resets on restart). Production multi-replica swap to `storage: 'database'` planned for a follow-up once the rateLimit migration is run. Also: in production, trust X-Forwarded-For / X-Real-IP so the IP that rate-limit + audit logging see is the real client, not the proxy. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -109,6 +109,31 @@ function buildAuth() {
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
sameSite: 'strict' as const,
|
||||
},
|
||||
// Trust the X-Forwarded-For chain when running behind Caddy/Nginx in
|
||||
// production so the IP that rate-limit + audit logging see is the
|
||||
// real client, not the proxy. Skipped in dev (no proxy in front).
|
||||
ipAddress: {
|
||||
ipAddressHeaders: isProd ? ['x-forwarded-for', 'x-real-ip'] : [],
|
||||
},
|
||||
},
|
||||
|
||||
// Rate limiting (post-audit F7) — without this, brute-force is wide
|
||||
// open. Tight caps on the credential-eating endpoints; loose default
|
||||
// for everything else so legitimate fan-out (multi-widget dashboards
|
||||
// that hit /get-session repeatedly) isn't hampered.
|
||||
rateLimit: {
|
||||
enabled: true,
|
||||
window: 60,
|
||||
max: 120,
|
||||
// Memory storage resets on restart. For multi-replica prod, swap
|
||||
// to `storage: 'database'` once the rateLimit migration is run.
|
||||
storage: 'memory',
|
||||
customRules: {
|
||||
'/sign-in/email': { window: 60, max: 5 },
|
||||
'/sign-up/email': { window: 60, max: 3 },
|
||||
'/forget-password': { window: 60, max: 3 },
|
||||
'/reset-password': { window: 60, max: 5 },
|
||||
},
|
||||
},
|
||||
|
||||
logger: {
|
||||
|
||||
Reference in New Issue
Block a user