UNPKG

nestjs-security-cli

Version:

Advanced IP blocking, role-based security, and attack detection for NestJS applications

272 lines (221 loc) โ€ข 7.21 kB
# NestJS Security CLI Advanced IP blocking, role-based security, and attack detection for NestJS applications. ## Requirements - Node.js >= 22.x - NestJS >= 11.x - TypeScript >= 5.x - You'll need to maintain the `@nestjs/cache-manager` and `cache-manager` packages. ## Installation ```bash npm install nestjs-security-cli ``` ## Quick Start ```typescript import { MiddlewareConsumer, Module, RequestMethod } from '@nestjs/common' import { MongooseModule } from '@nestjs/mongoose' import { SecurityModule, BlacklistedIp, BlacklistedIpSchema, SecurityMiddleware } from 'nestjs-security-cli' @Module( { imports: [ SecurityModule.forRootAsync( { enableAdminPanel: true, useFactory: () => ({ enableDatabase: true, defaultBlockDurationHours: 24, enableAutoBlocking: true }), imports: [ MongoDbModule ], providers: [ ...IpBlockerProvider ] } ) ] } ) export class AppModule { configure(consumer: MiddlewareConsumer): void { consumer .apply( SecurityMiddleware ) .forRoutes( { path: '*', method: RequestMethod.ALL } ) } } ``` ## DATABASE_CONNECTION provider if you're needing to use the database connection, and the import options isn't working, you can try to pass it directly into the providers array. ```text { provide: 'DATABASE_CONNECTION', inject: [ConfigService], useFactory: (configService: ConfigService): Promise<typeof mongoose> => { return mongoose.connect(configService.get<string>('DATABASE_HOST'), { dbName: configService.get<string>('DATABASE_NAME') }) } ``` ## with forRoot ```typescript import { MiddlewareConsumer, Module, RequestMethod } from '@nestjs/common' import { ConfigModule, ConfigService } from '@nestjs/config' import { MongooseModule } from '@nestjs/mongoose' import { SecurityModule, BlacklistedIp, BlacklistedIpSchema } from 'nestjs-security-cli' @Module( { imports: [ ConfigModule.forRoot(), MongoDbModule, SecurityModule.forRoot( { enableDatabase: true, defaultBlockDurationHours: 24, enableAutoBlocking: true, enableAdminPanel: true, } ), ], providers: [ ...IpBlockerProvider ], // Required if enableDatabase is true } ) export class AppModule { } export class AppModule { configure(consumer: MiddlewareConsumer): void { consumer .apply( SecurityMiddleware ) .forRoutes( { path: '*', method: RequestMethod.ALL } ) } } ``` ## Cache-Only Mode (No Database) If you don't want to use MongoDB, you can skip the schema registration: ```typescript import { Module } from '@nestjs/common' import { SecurityModule } from 'nestjs-security-cli' @Module( { imports: [ SecurityModule.forRoot( { enableDatabase: false, // This will use only cache defaultBlockDurationHours: 24, enableAutoBlocking: true } ) ] } ) export class AppModule { configure(consumer: MiddlewareConsumer): void { consumer .apply( SecurityMiddleware ) .forRoutes( { path: '*', method: RequestMethod.ALL } ) } } ```` ## SecurityService Since this has switched to using the `@Inject('IP_BLOCKER')` model to be registered in your app. So by passing the IpBlockerProvider, it will automatically register the model. More on this down below. ## Clean up cron There's a cron that runs to clean up old blocks. By default, it runs every 10 minutes. You can change this by setting the `CLEANUP_CRON` environment variable. ```text // Cleanup expired entries (runs daily) @Cron(CronExpression.EVERY_DAY_AT_MIDNIGHT) async cleanupExpiredBlocks(): Promise<void> { const result = await this.blacklistedIpModel.updateMany( { active: true, expiresAt: { $lt: new Date() } }, { active: false } ) console.log(`๐Ÿงน Cleaned up ${result.modifiedCount} expired IP blocks`) } ``` ## Role type The roles that can be defined in your app. Persist the roles in your user model as an array of strings. ```text export type Role = 'Admin' | 'User' | 'Moderator' | 'Guest' ``` ## Register the IpBlacklistGuard globally ```typescript import { Module, APP_GUARD } from '@nestjs/common' /* other imports */ import { IpBlacklistGuard } from 'nestjs-security-cli' @Module( { imports: [ /* other imports */ ], providers: [ { provide: APP_GUARD, useClass: IpBlacklistGuard // Register globally } ] } ) export class AppModule { } ``` And then in your controllers simply use the `@UseGuards(IpBlacklistGuard)` decorator. ## Admin & Roles guards * The Admin guard accepts ONLY users with the role `Admin`. * The Role guard accepts users with ane of (or all) the type "Roles" [as mentioned above](#role-type). * To leverage the admin panel, you'll need to create a role called `Admin`. The user model in your app should have a field called "Roles", which is an array of strings. To use the `AdminGuard` just add the decorator to your controller method. ```typescript @UseGuards( AdminGuard ) @Controller( 'my-contoller' ) ``` To use the `RoleGuard` just add the decorator to your controller method. ```typescript @Roles( 'Admin', 'User' ) @UseGuards( RoleGuard ) ``` The `AdminGuard` uses both `JwtService` and `ConfigService` to verify the JWT token. So if you're using this in your app, just make sure that the env var is `JWT_SECRET` and this will work. ( This could be dynamic later ). Also, when passing the token to the methods, you'll need to pass the token as `access_token` in either the request cookies, or the header authorization bearer token. ```typescript const user = await this.jwtService.verifyAsync( token, { secret: this.configService.get<string>( 'JWT_SECRET' ) } ) ``` ## The admin panel To use the built-in admin panel, you can set the `enableAdminPanel: true` in the configs [as shown in the](#quick-start) to set the available endpoints. Available endpoints: - POST `/security/blacklist`. This will accept a JSON object with the following fields: - `ip`: The IP address to blacklist - `hours`: The duration of the blacklist in hours - `reason`: The reason for the blacklist - GET `/security/blacklist`. This will return a list of all blacklisted IPs - GET `/security/blacklist/:ip`. This will return the details of a specific IP address - DELETE `/security/blacklist/:ip`. This will delete a specific IP address - GET `/security/analytics`. This will return analytics for the last 24 hours ## Features - ๐Ÿ›ก๏ธ IP Blacklisting with MongoDB persistence - ๐Ÿšซ Automatic attack pattern detection - โšก Redis/Memory caching for fast lookups - ๐Ÿ‘ฅ Role-based access control (RBAC) - ๐Ÿ“Š Security analytics and reporting - โฐ Scheduled cleanup of expired blocks ## Configuration Options ```typescript export interface SecurityConfigInterface { enableDatabase?: boolean mongooseConnection?: string cache?: { ttl?: number max?: number store?: any } enableAdminPanel?: boolean adminPath?: string enableAutoBlocking?: boolean suspiciousPatterns?: Array<{ pattern: string name: string blockDurationHours?: number }> defaultBlockDurationHours?: number enableRateLimit?: boolean rateLimitOptions?: { windowMs?: number max?: number } enableLogging?: boolean logLevel?: 'error' | 'warn' | 'info' | 'debug' } ``` ## API Documentation [coming soon] ## License MIT