UNPKG

nestjs-security-module

Version:

A plug-and-play NestJS security module with CORS, Helmet, rate limiting, audit logging, CSP, XSS sanitization, and more.

293 lines (235 loc) β€’ 10.3 kB
# NestJS Security Module πŸ” [![npm version](https://badge.fury.io/js/nestjs-security-module.svg)](https://badge.fury.io/js/nestjs-security-module) [![Downloads/week](https://img.shields.io/npm/dw/nestjs-security-module.svg)]() > A plug-and-play security module for NestJS, bundling best-practice HTTP headers, CORS, rate-limiting, audit logging, CSP, XSS sanitization and more. --- ## Table of Contents 1. [Features](#features) 2. [Installation](#installation) 3. [Basic Usage](#basic-usage) 4. [Async / Env-Based Configuration](#async--env-based-configuration) 5. [Options Reference](#options-reference) 6. [CORS Configuration](#cors-configuration) 7. [Example `.env`](#example-env) 8. [Troubleshooting](#troubleshooting) --- ## Features - πŸ”’ **Helmet** integration for standard security headers - 🌐 **Enhanced CORS** support with preflight request handling and case-sensitive headers - πŸ›‘οΈ **Rate Limiting** (per-IP) - πŸ“‹ **Audit Logging** (to console + file) - πŸ›‘ **Content-Security-Policy** (CSP) - 🧹 **XSS Sanitization** (deep sanitize middleware) - βš™οΈ Additional headers: Referrer-Policy, HSTS, Expect-CT, Permissions-Policy, COEP …and more --- ## Installation ```bash npm install nestjs-security-module # or yarn add nestjs-security-module ``` --- ## Basic Usage Import and configure the module in your `AppModule`: ```ts // app.module.ts import { Module } from '@nestjs/common'; import { SecurityModule } from 'nestjs-security-module'; @Module({ imports: [ SecurityModule.forRoot({ helmet: true, cors: { origin: 'http://localhost:3000', methods: ['GET', 'HEAD', 'POST'], allowedHeaders: ['Content-Type', 'content-type', 'Authorization', 'Accept', 'Origin', 'X-Requested-With'], credentials: true, }, rateLimit: { windowMs: 60_000, max: 10 }, auditLog: true, csp: true, sanitize: true, referrerPolicy: true, xFrameOptions: 'SAMEORIGIN', hsts: true, expectCt: true, permissionsPolicy: { geolocation: ['self'] }, crossOriginEmbedderPolicy: true, }), // … your other modules ], }) export class AppModule {} ``` --- ## Async / Env-Based Configuration If you prefer loading options from environment variables via `@nestjs/config`, use the async API: ```ts // app.module.ts import { Module } from '@nestjs/common'; import { ConfigModule, ConfigService } from '@nestjs/config'; import { SecurityModule } from 'nestjs-security-module'; @Module({ imports: [ ConfigModule.forRoot({ isGlobal: true }), SecurityModule.forRootAsync({ imports: [ConfigModule], inject: [ConfigService], useFactory: (cfg: ConfigService) => ({ helmet: cfg.get<boolean>('SECURITY_HELMET'), cors: cfg.get<boolean>('SECURITY_CORS') ? { origin: cfg.get<string>('CORS_ORIGIN'), methods: cfg.get<string>('CORS_METHODS').split(','), allowedHeaders: ['Content-Type', 'content-type', 'Authorization', 'Accept', 'Origin', 'X-Requested-With'], credentials: true, } : undefined, rateLimit: cfg.get<boolean>('SECURITY_RATE_LIMIT') ? { windowMs: cfg.get<number>('RATE_LIMIT_WINDOW'), max: cfg.get<number>('RATE_LIMIT_MAX'), } : undefined, auditLog: cfg.get<boolean>('SECURITY_AUDIT_LOG'), csp: cfg.get<boolean>('SECURITY_CSP') ? { directives: { defaultSrc: ["'self'"] } } : undefined, sanitize: cfg.get<boolean>('SECURITY_SANITIZE'), referrerPolicy: cfg.get<boolean>('SECURITY_REFERRER'), xFrameOptions: cfg.get<boolean>('SECURITY_XFRAME') ? 'SAMEORIGIN' : undefined, hsts: cfg.get<boolean>('SECURITY_HSTS') ? { maxAge: parseInt(cfg.get<string>('SECURITY_HSTS_MAX_AGE')) } : undefined, xContentTypeOptions: cfg.get<boolean>('SECURITY_XCONTENT_TYPE_OPTIONS'), expectCt: cfg.get<boolean>('SECURITY_EXPECT_CT') ? { maxAge: parseInt(cfg.get<string>('SECURITY_EXPECT_CT_MAX_AGE')) } : undefined, permissionsPolicy: cfg.get<boolean>('SECURITY_PERMISSIONS') ? { geolocation: ['self'] } : undefined, crossOriginEmbedderPolicy: cfg.get<boolean>('SECURITY_COEP'), }), }), ], }) export class AppModule {} ``` --- ## Options Reference | Option | Type | Description | | --------------------------- | ------------------------------------------------ | ------------------------------------------- | | `helmet` | `boolean` | Enable Helmet middleware | | `cors` | `boolean \| CORSConfig` | Enable/customize CORS with enhanced support | | `rateLimit` | `{ windowMs: number; max: number }` | IP-based rate limiting | | `auditLog` | `boolean` | Log requests to console + file | | `csp` | `boolean \| object` | Enable CSP (Content Security Policy) | | `sanitize` | `boolean` | Deep sanitize incoming payloads | | `referrerPolicy` | `boolean \| object` | Set Referrer-Policy header | | `xFrameOptions` | `boolean \| 'DENY' \| 'SAMEORIGIN'` | Set X-Frame-Options header | | `hsts` | `boolean \| object` | Enforce HTTPS via Strict-Transport-Security | | `xContentTypeOptions` | `boolean` | Prevent MIME sniffing | | `expectCt` | `boolean \| object` | Set Expect-CT header | | `permissionsPolicy` | `boolean \| Record<string, string[]>` | Set Permissions-Policy header | | `crossOriginEmbedderPolicy` | `boolean \| object` | Enable COEP header | --- ## CORS Configuration The CORS configuration has been enhanced with the following improvements: ### Enhanced CORS Options ```ts interface CORSConfig { origin: string; methods: string[] | string; allowedHeaders?: string[]; credentials?: boolean; } ``` ### Key Improvements - βœ… **Preflight Request Handling**: Automatic OPTIONS request handling - βœ… **Case-Sensitive Headers**: Support for both `Content-Type` and `content-type` - βœ… **Array/String Methods**: Support for both array and string method definitions - βœ… **Credentials Support**: Proper handling of credentials in CORS requests - βœ… **Max-Age Caching**: 24-hour preflight response caching ### Example CORS Configuration ```ts cors: { origin: 'http://localhost:3000', methods: ['GET', 'HEAD', 'POST'], // Array format // or methods: 'GET,HEAD,POST', // String format allowedHeaders: ['Content-Type', 'content-type', 'Authorization', 'Accept', 'Origin', 'X-Requested-With'], credentials: true, } ``` ### Manual OPTIONS Endpoint (Optional) For additional control, you can add a manual OPTIONS endpoint: ```ts // app.controller.ts import { Controller, Options, Res } from '@nestjs/common'; import { Response } from 'express'; @Controller() export class AppController { @Options() handleOptions(@Res() res: Response): void { res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000'); res.setHeader('Access-Control-Allow-Methods', 'GET,HEAD,POST,OPTIONS'); res.setHeader('Access-Control-Allow-Headers', 'Content-Type,content-type,Authorization,Accept,Origin,X-Requested-With'); res.setHeader('Access-Control-Allow-Credentials', 'true'); res.setHeader('Access-Control-Max-Age', '86400'); res.status(200).end(); } } ``` --- ## Example `.env` ```dotenv SECURITY_HELMET=true SECURITY_CORS=true CORS_ORIGIN=http://localhost:3000 CORS_METHODS=GET,HEAD,POST SECURITY_RATE_LIMIT=true RATE_LIMIT_WINDOW=60000 RATE_LIMIT_MAX=10 SECURITY_AUDIT_LOG=true SECURITY_CSP=true SECURITY_SANITIZE=true SECURITY_REFERRER=true SECURITY_XFRAME=true SECURITY_HSTS=true SECURITY_HSTS_MAX_AGE=31536000 SECURITY_XCONTENT_TYPE_OPTIONS=true SECURITY_EXPECT_CT=true SECURITY_EXPECT_CT_MAX_AGE=30 SECURITY_PERMISSIONS=true SECURITY_COEP=true ``` --- ## Troubleshooting ### CORS Issues If you encounter CORS errors, ensure: 1. **Origin is correctly set**: Use specific origin instead of wildcard `*` 2. **Headers are case-sensitive**: Include both `Content-Type` and `content-type` 3. **Methods are properly formatted**: Use array format for better compatibility 4. **Credentials are enabled**: Set `credentials: true` for authenticated requests ### Rate Limiting - Rate limiting is per-IP address - Default: 10 requests per 60 seconds - Configure via `RATE_LIMIT_WINDOW` and `RATE_LIMIT_MAX` environment variables ### Security Headers All security headers are automatically applied when enabled: - `Content-Security-Policy` - `Strict-Transport-Security` - `X-Frame-Options` - `X-Content-Type-Options` - `Referrer-Policy` - `Permissions-Policy` - `Cross-Origin-Embedder-Policy` --- ## Testing Test your CORS configuration: ```bash # Test preflight request curl -v -H "Origin: http://localhost:3000" \ -H "Access-Control-Request-Method: POST" \ -H "Access-Control-Request-Headers: content-type" \ -X OPTIONS http://localhost:3001 # Test regular request curl -v -H "Origin: http://localhost:3000" \ -H "Content-Type: application/json" \ -X POST http://localhost:3001 ``` --- ## Contributing This module includes enhanced CORS support and improved security features. For issues or contributions, please refer to the project repository. ---