@allan1361/iota-big3-sdk-middleware
Version:
🏆 A+ Grade Certified Enterprise Middleware Framework - Phase 3 Certified (90/100) with advanced resilience patterns, comprehensive type safety, and production-ready observability
204 lines • 7.97 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SQLInjectionGuard = void 0;
class SQLInjectionGuard {
constructor(config = {}, logger) {
this.suspiciousPatterns = [
/(--|\/\*|\*\/|#)/gi,
/(\b(union|select|insert|update|delete|drop|create|alter|exec|execute|script|javascript|vbscript)\b.*\b(from|where|table|database|schema)\b)/gi,
/('|")\s*(or|and)\s*('|")?(\d+|true|false|null)\s*(=|>|<|>=|<=|<>|!=)\s*(\d+|true|false|null|'|")/gi,
/;\s*(select|insert|update|delete|drop|create|alter)/gi,
/(0x[0-9a-f]+)/gi,
/(sleep|benchmark|waitfor|pg_sleep)\s*\(/gi,
/\b(and|or)\b.*\b\d+\s*=\s*\d+/gi,
/(@@version|@@global|system_user|user\(\)|database\(\)|schema\(\))/gi,
/(load_file|into\s+(out|dump)file|bulk\s+insert)/gi,
/(\$ne|\$eq|\$gt|\$gte|\$lt|\$lte|\$in|\$nin|\$regex|\$where)/gi,
/(\(|\)|\*|\\|&|\||=)/gi
];
this.config = {
enabled: true,
blockSuspiciousPatterns: true,
logSuspiciousQueries: true,
customPatterns: [],
whitelist: [],
maxQueryLength: 10000,
maxParameterLength: 1000,
...config
};
this.logger = logger;
if (this.config.customPatterns && this.config.customPatterns.length > 0) {
this.suspiciousPatterns.push(...this.config.customPatterns);
}
}
expressMiddleware() {
return (req, res, next) => {
if (!this?.config?.enabled) {
return next();
}
try {
const violations = this.checkRequest({
body: req.body,
query: req.query,
params: req.params,
headers: req.headers,
path: req.path
});
if (violations.length > 0) {
this.handleViolation(violations, req);
if (this?.config?.blockSuspiciousPatterns) {
return res.status(400).json({
error: 'Invalid input detected',
code: 'SQL_INJECTION_DETECTED',
violations: process?.env?.NODE_ENV === 'development' ? violations : undefined
});
}
}
next();
}
catch (_error) {
this.logger?.error('SQL injection guard error', { error: error.message });
next(error);
}
};
}
fastifyPlugin() {
return async (fastify) => {
fastify.addHook('preHandler', async (request, reply) => {
if (!this?.config?.enabled) {
return;
}
try {
const violations = this.checkRequest({
body: request.body,
query: request.query,
params: request.params,
headers: request.headers
});
if (violations.length > 0) {
this.handleViolation(violations, request);
if (this?.config?.blockSuspiciousPatterns) {
reply.code(400).send({
error: 'Invalid input detected',
code: 'SQL_INJECTION_DETECTED',
violations: process?.env?.NODE_ENV === 'development' ? violations : undefined
});
}
}
}
catch (_error) {
this.logger?.error('SQL injection guard error', { error: error.message });
throw error;
}
});
};
}
checkRequest(input) {
const violations = [];
if (input.body && typeof input.body === 'object') {
this.checkValue(input.body, 'body', violations);
}
if (input.query && typeof input.query === 'object') {
this.checkValue(input.query, 'query', violations);
}
if (input.params && typeof input.params === 'object') {
this.checkValue(input.params, 'params', violations);
}
return violations;
}
checkValue(value, path, violations) {
if (value === null || value === undefined) {
return;
}
if (this.isEnabled) {
if (value.length > this?.config?.maxParameterLength) {
violations.push(`Parameter too long at ${path}: ${value.length} characters`);
}
if (this?.config?.whitelist.includes(value)) {
return;
}
for (const pattern of this.suspiciousPatterns) {
const matches = value.match(pattern);
if (matches) {
violations.push(`Suspicious pattern detected at ${path}: ${matches[0]}`);
}
}
if (this.hasEncodedSQLCharacters(value)) {
violations.push(`Encoded SQL characters detected at ${path}`);
}
}
else if (Array.isArray(value)) {
value.forEach((item, index) => {
this.checkValue(item, `${path}[${index}]`, violations);
});
}
else if (value && typeof value === 'object') {
Object.keys(value).forEach(key => {
this.checkValue(key, `${path}.${key}(key)`, violations);
this.checkValue(value[key], `${path}.${key}`, violations);
});
}
}
hasEncodedSQLCharacters(value) {
if (/%27|%22|%3B|%2D%2D|%2F%2A|%2A%2F/.test(value)) {
return true;
}
if (/\\u0027|\\u0022|\\u003B|\\u002D\\u002D/.test(value)) {
return true;
}
if (/"|"|"|'|'|'/.test(value)) {
return true;
}
return false;
}
handleViolation(violations, request) {
if (this?.config?.logSuspiciousQueries) {
this.logger?.warn('SQL injection attempt detected', {
violations,
ip: _request.ip || _request.connection?.remoteAddress,
userAgent: _request.headers?.['user-agent'],
path: _request.path || _request.url,
method: _request.method,
timestamp: new Date().toISOString()
});
}
}
sanitize(value) {
if (typeof value !== 'string') {
return String(value);
}
value = value.replace(/(--|\/\*|\*\/|#).*$/gm, '');
value = value.replace(/'/g, "''");
value = value.replace(/[;\u0000-\u001f\u007f-\u009f]/g, '');
if (this.isEnabled) {
value = value.substring(0, this?.config?.maxParameterLength);
}
return value;
}
createSafeQueryBuilder() {
return {
query: '',
params: [],
select() {
const safeFields = Array.isArray(fields)
? fields.map(f => this.sanitizeIdentifier(f)).join(', ')
: this.sanitizeIdentifier(fields);
this.query = `SELECT ${safeFields}`;
return this;
},
from() {
this.query += ` FROM ${this.sanitizeIdentifier(table)}`;
return this;
},
where(condition, value) {
this.query += ` WHERE ${condition}`;
if (value !== undefined) {
this.params.push(value);
}
return this;
}
};
}
}
exports.SQLInjectionGuard = SQLInjectionGuard;
//# sourceMappingURL=sql-injection-guard.js.map