diff --git a/README.md b/README.md index f249c7a..cf0392a 100644 --- a/README.md +++ b/README.md @@ -259,8 +259,8 @@ This application implements enterprise-grade security following OWASP best pract - Protection against session fixation attacks 5. **Account Lockout (Dual-Layer Brute Force Protection)** - - IP-based rate limiting (existing) - - Per-account lockout: 10 failed attempts = 30 minute lock + - IP-based rate limiting: 5 failed attempts = 15 minute lockout + - Per-account lockout: 5 failed attempts = 15 minute lock - Automatic unlock after expiration - Admin manual unlock capability via UI diff --git a/server/api/auth/login.post.ts b/server/api/auth/login.post.ts index b8c1940..4b3be2d 100644 --- a/server/api/auth/login.post.ts +++ b/server/api/auth/login.post.ts @@ -57,7 +57,7 @@ export default defineEventHandler(async (event) => { console.log(`[LOGIN BLOCKED] Account locked - User: ${username.toLowerCase()}, IP: ${clientIp}`) throw createError({ statusCode: 403, - message: 'Account temporarily locked due to too many failed login attempts. Please try again in 30 minutes or contact an administrator.' + message: 'Account temporarily locked due to too many failed login attempts. Please try again in 15 minutes or contact an administrator.' }) } diff --git a/server/utils/database.ts b/server/utils/database.ts index 448ed49..392f6fb 100644 --- a/server/utils/database.ts +++ b/server/utils/database.ts @@ -469,17 +469,19 @@ export function incrementFailedAttempts(username: string): void { if (!user) return const newAttempts = (user.failed_login_attempts || 0) + 1 - const maxAttempts = 10 + const maxAttempts = 5 // Aligned with IP rate limiting if (newAttempts >= maxAttempts) { - // Lock account for 30 minutes - const lockUntil = new Date(Date.now() + 30 * 60 * 1000).toISOString() + // Lock account for 15 minutes (aligned with IP rate limiting) + const lockUntil = new Date(Date.now() + 15 * 60 * 1000).toISOString() db.prepare('UPDATE users SET failed_login_attempts = ?, locked_until = ? WHERE username = ?') .run(newAttempts, lockUntil, username) + console.log(`[ACCOUNT LOCKED] User ${username} locked after ${newAttempts} failed attempts until ${lockUntil}`) } else { // Just increment counter db.prepare('UPDATE users SET failed_login_attempts = ? WHERE username = ?') .run(newAttempts, username) + console.log(`[ACCOUNT SECURITY] Failed login attempt #${newAttempts} for user: ${username}`) } }