e35ac6a41c
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>
108 lines
4.2 KiB
JavaScript
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);
|
|
} |