zurri / src /middlewares /security.ts
nexusbert's picture
push
9c67ac5
import { Request, Response, NextFunction } from 'express';
import rateLimit from 'express-rate-limit';
export const requestLogger = (req: Request, res: Response, next: NextFunction) => {
const start = Date.now();
res.on('finish', () => {
const duration = Date.now() - start;
console.log(`${req.method} ${req.path} ${res.statusCode} - ${duration}ms - ${req.ip}`);
});
next();
};
export const sanitizeRequestBody = (req: Request, res: Response, next: NextFunction) => {
if (req.body && typeof req.body === 'object') {
const sanitize = (obj: any): any => {
if (Array.isArray(obj)) {
return obj.map(sanitize);
}
if (obj && typeof obj === 'object') {
const sanitized: any = {};
for (const key in obj) {
if (typeof obj[key] === 'string') {
// Basic XSS prevention - remove script tags
sanitized[key] = obj[key].replace(/<script[^>]*>.*?<\/script>/gi, '');
} else {
sanitized[key] = sanitize(obj[key]);
}
}
return sanitized;
}
return obj;
};
req.body = sanitize(req.body);
}
next();
};
export const validateRequestSize = (maxSize: number = 10485760) => {
return (req: Request, res: Response, next: NextFunction) => {
const contentLength = parseInt(req.headers['content-length'] || '0', 10);
if (contentLength > maxSize) {
return res.status(413).json({ error: 'Request entity too large' });
}
next();
};
};
export const createStrictRateLimiter = (windowMs: number, max: number) => {
return rateLimit({
windowMs,
max,
message: 'Too many requests from this IP, please try again later.',
standardHeaders: true,
legacyHeaders: false,
// Trust proxy is set to 1 in app.ts, so express-rate-limit will handle X-Forwarded-For correctly
});
};
export const createAuthRateLimiter = () => {
return rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 5,
message: 'Too many authentication attempts. Please try again later.',
skipSuccessfulRequests: true,
standardHeaders: true,
legacyHeaders: false,
});
};
export const createPasswordResetRateLimiter = () => {
return rateLimit({
windowMs: 60 * 60 * 1000, // 1 hour
max: 3,
message: 'Too many password reset requests. Please try again later.',
standardHeaders: true,
legacyHeaders: false,
});
};