feat: implement critical security fixes for SQL injection and authentication vulnerabilities
Test Gitea Actions / test (push) Successful in 20s
continuous-integration/drone/push Build is passing

Security Enhancements:
- Fix SQL injection vulnerabilities by replacing whereRaw queries with parameterized queries
- Add LIKE pattern escaping to prevent SQL injection in search functionality
- Implement account lockout protection (5 failed attempts = 30 min lockout)
- Add comprehensive login attempt tracking and audit trail
- Enhance JWT tokens with issuer validation, IP tracking, and password change detection
- Add logout endpoint and session management
- Prevent user enumeration with generic error messages

Database Changes:
- Add login_attempts table for authentication tracking
- Add security columns to admin_users (password_changed_at, last_login_ip, two_factor_enabled)

New Security Features:
- Brute force protection with configurable lockout duration
- Automatic cleanup of old login attempts
- Enhanced authentication middleware with stricter validation
- Monitoring scripts for security health checks

All fixes are backward compatible and production-ready with rollback plans included.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-07-13 00:40:05 +02:00
parent 0d33f21ee6
commit e35ac6a41c
36 changed files with 4152 additions and 20 deletions
+3 -1
View File
@@ -6,6 +6,7 @@ const { db, logActivity } = require('../database/db');
const { adminAuth } = require('../middleware/auth');
const { generateThumbnail } = require('../services/imageProcessor');
const { generatePhotoFilename } = require('../utils/filenameSanitizer');
const { escapeLikePattern } = require('../utils/sqlSecurity');
const router = express.Router();
// Get storage path from environment or default
@@ -473,7 +474,8 @@ router.get('/:eventId/photos', adminAuth, async (req, res) => {
// Search by filename
if (search) {
query = query.where('photos.filename', 'like', `%${search}%`);
const escapedSearch = escapeLikePattern(search);
query = query.where('photos.filename', 'like', `%${escapedSearch}%`);
}
// Sorting