Files
picpeak/backend/scripts/test-sql-security.js
T
paul e35ac6a41c
Test Gitea Actions / test (push) Successful in 20s
continuous-integration/drone/push Build is passing
feat: implement critical security fixes for SQL injection and authentication vulnerabilities
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>
2025-07-13 00:40:05 +02:00

108 lines
4.2 KiB
JavaScript

#!/usr/bin/env node
/**
* Test script to verify SQL security fixes work correctly
* Tests both functionality and security of the fixes
*/
const {
sanitizeDays,
escapeLikePattern,
validateSortColumn,
validateSortOrder
} = require('../src/utils/sqlSecurity');
console.log('=== Testing SQL Security Utilities ===\n');
let passed = 0;
let failed = 0;
function test(description, fn) {
try {
const result = fn();
if (result) {
console.log(`${description}`);
passed++;
} else {
console.log(`${description}`);
failed++;
}
} catch (error) {
console.log(`${description} - Error: ${error.message}`);
failed++;
}
}
// Test sanitizeDays
console.log('Testing sanitizeDays function:');
test('Valid number returns same number', () => sanitizeDays(7) === 7);
test('String number is parsed correctly', () => sanitizeDays('30') === 30);
test('Invalid input returns default 7', () => sanitizeDays('abc') === 7);
test('Negative number returns 1', () => sanitizeDays(-5) === 1);
test('Zero returns 1', () => sanitizeDays(0) === 1);
test('Large number is capped at 365', () => sanitizeDays(500) === 365);
test('NaN returns default 7', () => sanitizeDays(NaN) === 7);
test('Null returns default 7', () => sanitizeDays(null) === 7);
test('Undefined returns default 7', () => sanitizeDays(undefined) === 7);
// Test escapeLikePattern
console.log('\nTesting escapeLikePattern function:');
test('Normal text unchanged', () => escapeLikePattern('hello world') === 'hello world');
test('Percent sign escaped', () => escapeLikePattern('50%') === '50\\%');
test('Underscore escaped', () => escapeLikePattern('user_name') === 'user\\_name');
test('Backslash escaped', () => escapeLikePattern('path\\to\\file') === 'path\\\\to\\\\file');
test('Multiple special chars escaped', () => escapeLikePattern('50%_test\\') === '50\\%\\_test\\\\');
test('Empty string returns empty', () => escapeLikePattern('') === '');
test('Null returns empty string', () => escapeLikePattern(null) === '');
test('Undefined returns empty string', () => escapeLikePattern(undefined) === '');
test('Single quotes escaped', () => escapeLikePattern("O'Brien") === "O''Brien");
// Test SQL injection attempts
console.log('\nTesting SQL injection prevention:');
test('SQL injection attempt with quotes', () => {
const malicious = "'; DROP TABLE users; --";
const escaped = escapeLikePattern(malicious);
return escaped === "''; DROP TABLE users; --" && escaped.includes("''");
});
test('SQL injection with LIKE wildcards', () => {
const malicious = "%' OR 1=1 --";
const escaped = escapeLikePattern(malicious);
return escaped === "\\%'' OR 1=1 --";
});
test('Days parameter injection attempt', () => {
const malicious = "7; DROP TABLE events; --";
return sanitizeDays(malicious) === 7;
});
// Test validateSortColumn
console.log('\nTesting validateSortColumn function:');
const allowedColumns = ['name', 'date', 'size'];
test('Valid column accepted', () => validateSortColumn('name', allowedColumns, 'date') === 'name');
test('Invalid column returns default', () => validateSortColumn('price', allowedColumns, 'date') === 'date');
test('Null returns default', () => validateSortColumn(null, allowedColumns, 'date') === 'date');
test('Empty string returns default', () => validateSortColumn('', allowedColumns, 'date') === 'date');
// Test validateSortOrder
console.log('\nTesting validateSortOrder function:');
test('Valid asc accepted', () => validateSortOrder('asc') === 'asc');
test('Valid ASC accepted', () => validateSortOrder('ASC') === 'asc');
test('Valid desc accepted', () => validateSortOrder('desc') === 'desc');
test('Invalid order returns desc', () => validateSortOrder('random') === 'desc');
test('Null returns desc', () => validateSortOrder(null) === 'desc');
test('Empty returns desc', () => validateSortOrder('') === 'desc');
// Summary
console.log('\n=== Test Summary ===');
console.log(`Total tests: ${passed + failed}`);
console.log(`Passed: ${passed}`);
console.log(`Failed: ${failed}`);
if (failed === 0) {
console.log('\n✅ All tests passed! SQL security utilities are working correctly.');
process.exit(0);
} else {
console.log('\n❌ Some tests failed. Please check the implementation.');
process.exit(1);
}