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,61 @@
|
||||
import { BadRequestException, Injectable, type PipeTransform } from '@nestjs/common';
|
||||
|
||||
export interface UploadedFile {
|
||||
fieldname: string;
|
||||
originalname: string;
|
||||
encoding: string;
|
||||
mimetype: string;
|
||||
size: number;
|
||||
buffer: Buffer;
|
||||
}
|
||||
|
||||
export interface FileValidationOptions {
|
||||
/** Max file size in bytes. Default: 5 MB */
|
||||
maxSizeBytes?: number;
|
||||
/** Allowed MIME types. Default: common image types + PDF */
|
||||
allowedMimeTypes?: string[];
|
||||
}
|
||||
|
||||
const DEFAULT_MAX_SIZE = 5 * 1024 * 1024; // 5 MB
|
||||
const DEFAULT_ALLOWED_MIMES = [
|
||||
'image/jpeg',
|
||||
'image/png',
|
||||
'image/webp',
|
||||
'image/gif',
|
||||
'application/pdf',
|
||||
];
|
||||
|
||||
/**
|
||||
* Validates uploaded files for size and MIME type to prevent
|
||||
* malicious file uploads and resource exhaustion.
|
||||
*/
|
||||
@Injectable()
|
||||
export class FileValidationPipe implements PipeTransform {
|
||||
private readonly maxSize: number;
|
||||
private readonly allowedMimes: string[];
|
||||
|
||||
constructor(options?: FileValidationOptions) {
|
||||
this.maxSize = options?.maxSizeBytes ?? DEFAULT_MAX_SIZE;
|
||||
this.allowedMimes = options?.allowedMimeTypes ?? DEFAULT_ALLOWED_MIMES;
|
||||
}
|
||||
|
||||
transform(file: UploadedFile): UploadedFile {
|
||||
if (!file) {
|
||||
throw new BadRequestException('File is required');
|
||||
}
|
||||
|
||||
if (file.size > this.maxSize) {
|
||||
throw new BadRequestException(
|
||||
`File size ${file.size} exceeds maximum allowed size of ${this.maxSize} bytes`,
|
||||
);
|
||||
}
|
||||
|
||||
if (!this.allowedMimes.includes(file.mimetype)) {
|
||||
throw new BadRequestException(
|
||||
`File type '${file.mimetype}' is not allowed. Allowed types: ${this.allowedMimes.join(', ')}`,
|
||||
);
|
||||
}
|
||||
|
||||
return file;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user