Advanced IP blocking, role-based security, and attack detection for NestJS applications
npm install nestjs-security-cliAdvanced IP blocking, role-based security, and attack detection for NestJS applications.
- Node.js >= 22.x
- NestJS >= 11.x
- TypeScript >= 5.x
- You'll need to maintain the @nestjs/cache-manager and cache-manager packages.
``bash`
npm install nestjs-security-cli
`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,
// example of customizing the suspicious patterns
suspiciousPatterns: [
{ pattern: '/vendor', name: 'Composer Attempt' },
{ pattern: '/phpunit', name: 'PHPUnit Attempt' },
{ pattern: '/lib', name: 'Lib Attempt' },
{ pattern: '/laravel', name: 'Laravel Attempt' },
{ pattern: '/www', name: 'WWW Attempt' },
{ pattern: '/ws', name: 'Web Socket Attempt' },
{ pattern: '/yii', name: 'Yii Attempt' },
{ pattern: '/zend', name: 'Zend Attempt' },
{ pattern: '/test', name: 'Test Attempt' },
{ pattern: '/tests', name: 'Tests Attempt' },
{ pattern: '/testing', name: 'Testing Attempt' },
{ pattern: '/cms', name: 'CMS Attempt' },
{ pattern: '/crm', name: 'CRM Attempt' }
]
}),
imports: [ MongoDbModule ],
providers: [ ...IpBlockerProvider ]
} )
]
} )
export class AppModule {
}
`
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
return mongoose.connect(configService.get
dbName: configService.get
})
}
`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 {}
`
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 {}
``
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.
There's a cron that runs to clean up old blocks. By default, it runs every day at midnight.
CLEANUP_CRON environment variable.
`text๐งน Cleaned up ${result.modifiedCount} expired IP blocks
// Cleanup expired entries (runs daily)
@Cron(CronExpression.EVERY_DAY_AT_MIDNIGHT)
async cleanupExpiredBlocks(): Promise
const result = await this.blacklistedIpModel.updateMany(
{ active: true, expiresAt: { $lt: new Date() } },
{ active: false }
)
console.log()`
}
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'
@UseGuards(IpBlacklistGuard) // add this to any, or all controller endpoints
@Controller()
export class AppController {
@Get()
someEndpoint(): object {
return { message: 'Hello World!' }
}
}
`
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.
* 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( '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 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 hoursFeatures
- ๐ก๏ธ 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'
}
``[coming soon]
MIT