feat(security): add security hardening — Helmet, CORS, rate limiting, input sanitization
- Add Helmet with CSP, HSTS, referrer policy - Configure CORS with environment-based origins - Add global validation pipe with whitelist mode - Add SanitizeInputMiddleware for XSS prevention - Add ThrottlerBehindProxyGuard for rate limiting - Add FileValidationPipe for upload security - Set request body size limit to 1MB Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
import { Injectable, type NestMiddleware } from '@nestjs/common';
|
||||
import type { NextFunction, Request, Response } from 'express';
|
||||
import sanitizeHtml from 'sanitize-html';
|
||||
|
||||
const SANITIZE_OPTIONS: sanitizeHtml.IOptions = {
|
||||
allowedTags: [],
|
||||
allowedAttributes: {},
|
||||
disallowedTagsMode: 'recursiveEscape',
|
||||
};
|
||||
|
||||
function sanitizeValue(value: unknown): unknown {
|
||||
if (typeof value === 'string') {
|
||||
return sanitizeHtml(value, SANITIZE_OPTIONS);
|
||||
}
|
||||
if (Array.isArray(value)) {
|
||||
return value.map(sanitizeValue);
|
||||
}
|
||||
if (value !== null && typeof value === 'object') {
|
||||
return sanitizeObject(value as Record<string, unknown>);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
function sanitizeObject(obj: Record<string, unknown>): Record<string, unknown> {
|
||||
const sanitized: Record<string, unknown> = {};
|
||||
for (const [key, val] of Object.entries(obj)) {
|
||||
sanitized[key] = sanitizeValue(val);
|
||||
}
|
||||
return sanitized;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strips HTML tags from all string values in request body, query, and params
|
||||
* to prevent stored XSS attacks.
|
||||
*/
|
||||
@Injectable()
|
||||
export class SanitizeInputMiddleware implements NestMiddleware {
|
||||
use(req: Request, _res: Response, next: NextFunction): void {
|
||||
if (req.body && typeof req.body === 'object') {
|
||||
req.body = sanitizeObject(req.body as Record<string, unknown>);
|
||||
}
|
||||
if (req.query && typeof req.query === 'object') {
|
||||
req.query = sanitizeObject(req.query as Record<string, unknown>) as typeof req.query;
|
||||
}
|
||||
if (req.params && typeof req.params === 'object') {
|
||||
req.params = sanitizeObject(req.params as Record<string, unknown>) as typeof req.params;
|
||||
}
|
||||
next();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user