@ordojs/security
Version:
Security package for OrdoJS with XSS, CSRF, and injection protection
173 lines • 6.28 kB
JavaScript
/**
* SQL Injection Prevention
* Provides comprehensive protection against SQL injection attacks
*/
export class SqlInjectionPrevention {
static SQL_INJECTION_PATTERNS = [
// Union-based injection patterns
{
pattern: /(\bunion\b.*\bselect\b)|(\bselect\b.*\bunion\b)/gi,
severity: 'critical',
description: 'UNION-based SQL injection attempt detected'
},
// Boolean-based blind injection
{
pattern: /(\b(and|or)\b\s*\d+\s*[=<>]\s*\d+)|(\b(and|or)\b\s*['"]?\w+['"]?\s*[=<>]\s*['"]?\w+['"]?)/gi,
severity: 'high',
description: 'Boolean-based blind SQL injection attempt detected'
},
// Time-based blind injection
{
pattern: /\b(sleep|waitfor|delay|benchmark)\s*\(/gi,
severity: 'critical',
description: 'Time-based blind SQL injection attempt detected'
},
// Error-based injection
{
pattern: /\b(extractvalue|updatexml|exp|floor|rand)\s*\(/gi,
severity: 'high',
description: 'Error-based SQL injection attempt detected'
},
// Stacked queries
{
pattern: /;\s*(drop|delete|insert|update|create|alter|exec|execute)\b/gi,
severity: 'critical',
description: 'Stacked query SQL injection attempt detected'
},
// Comment-based evasion
{
pattern: /(\/\*.*?\*\/)|(--.*)|(#.*)/g,
severity: 'medium',
description: 'SQL comment-based evasion attempt detected'
},
// Information schema access
{
pattern: /\binformation_schema\b/gi,
severity: 'high',
description: 'Information schema access attempt detected'
},
// System function calls
{
pattern: /\b(xp_cmdshell|sp_oacreate|sp_oamethod|openrowset|opendatasource)\b/gi,
severity: 'critical',
description: 'System function SQL injection attempt detected'
},
// Hex encoding evasion
{
pattern: /0x[0-9a-f]+/gi,
severity: 'medium',
description: 'Hex-encoded SQL injection attempt detected'
},
// Concatenation-based evasion
{
pattern: /\bconcat\s*\(|(\|\|)|(\+\s*['"])/gi,
severity: 'medium',
description: 'Concatenation-based SQL injection attempt detected'
}
];
/**
* Validates input for SQL injection patterns
*/
static validateInput(input) {
if (typeof input !== 'string') {
return { isValid: true, threats: [] };
}
const detectedThreats = [];
for (const pattern of this.SQL_INJECTION_PATTERNS) {
if (pattern.pattern.test(input)) {
detectedThreats.push(pattern);
}
}
return {
isValid: detectedThreats.length === 0,
threats: detectedThreats
};
}
/**
* Sanitizes input by removing or escaping SQL injection patterns
*/
static sanitizeInput(input, options = {}) {
if (typeof input !== 'string') {
return String(input);
}
let sanitized = input;
if (options.strict) {
// In strict mode, remove any detected patterns entirely
for (const pattern of this.SQL_INJECTION_PATTERNS) {
sanitized = sanitized.replace(pattern.pattern, '');
}
}
else {
// In normal mode, escape dangerous characters
sanitized = sanitized
.replace(/'/g, "''") // Escape single quotes
.replace(/"/g, '""') // Escape double quotes
.replace(/\\/g, '\\\\') // Escape backslashes
.replace(/;/g, '\\;') // Escape semicolons
.replace(/--/g, '\\-\\-') // Escape SQL comments
.replace(/\/\*/g, '\\/\\*') // Escape block comments
.replace(/\*\//g, '\\*\\/'); // Escape block comments
}
return sanitized.trim();
}
/**
* Creates a parameterized query-safe version of input
*/
static createSafeParameter(input) {
if (typeof input === 'string') {
return this.sanitizeInput(input, { strict: true });
}
if (typeof input === 'number' || typeof input === 'boolean') {
return input;
}
if (input === null || input === undefined) {
return null;
}
if (Array.isArray(input)) {
return input.map(item => this.createSafeParameter(item));
}
if (typeof input === 'object') {
const safeObject = {};
for (const [key, value] of Object.entries(input)) {
safeObject[this.sanitizeInput(key)] = this.createSafeParameter(value);
}
return safeObject;
}
return String(input);
}
/**
* Validates and sanitizes multiple inputs
*/
static validateAndSanitizeInputs(inputs) {
const allThreats = [];
const sanitizedInputs = {};
for (const [field, value] of Object.entries(inputs)) {
try {
const sanitized = this.createSafeParameter(value);
sanitizedInputs[field] = sanitized;
if (typeof value === 'string') {
const validation = this.validateInput(value);
if (!validation.isValid) {
allThreats.push({ field, threats: validation.threats });
}
}
}
catch (error) {
allThreats.push({
field,
threats: [{
pattern: /.*/,
severity: 'critical',
description: error instanceof Error ? error.message : 'Unknown SQL injection threat'
}]
});
}
}
return {
isValid: allThreats.length === 0,
threats: allThreats,
sanitizedInputs
};
}
}
//# sourceMappingURL=sql-injection-prevention.js.map