From 9198d4330cd1c4303e9f01ed313b63bfd4fcf044 Mon Sep 17 00:00:00 2001 From: Igor Propisnov Date: Fri, 3 May 2024 14:13:15 +0200 Subject: [PATCH] added csp middleware, redirect to https in prod and more security --- backend/src/app.module.ts | 7 +++++-- .../{csp-middleware.ts => csp.middleware.ts} | 1 - .../https-redirect.middleware.ts | 19 ++++++++++++++++++ .../security.middleware.ts | 20 +++++++++++++++++++ 4 files changed, 44 insertions(+), 3 deletions(-) rename backend/src/middleware/csp-middleware/{csp-middleware.ts => csp.middleware.ts} (94%) create mode 100644 backend/src/middleware/https-middlware/https-redirect.middleware.ts create mode 100644 backend/src/middleware/security-middleware/security.middleware.ts diff --git a/backend/src/app.module.ts b/backend/src/app.module.ts index 8d6ae9b..2b7d263 100644 --- a/backend/src/app.module.ts +++ b/backend/src/app.module.ts @@ -3,7 +3,9 @@ import { AppController } from './app.controller'; import { AppService } from './app.service'; import { ConfigModule } from '@nestjs/config'; import { DatabaseModule } from './modules/database-module/database.module'; -import { CspMiddleware } from './middleware/csp-middleware/csp-middleware'; +import { CspMiddleware } from './middleware/csp-middleware/csp.middleware'; +import { SecurityHeadersMiddleware } from './middleware/security-middleware/security.middleware'; +import { HttpsRedirectMiddleware } from './middleware/https-middlware/https-redirect.middleware'; @Module({ imports: [ @@ -18,7 +20,8 @@ import { CspMiddleware } from './middleware/csp-middleware/csp-middleware'; export class AppModule { configure(consumer: MiddlewareConsumer) { consumer - .apply(CspMiddleware) + // TODO: Redirect via Reverse Proxy all HTTP requests to HTTPS + .apply(CspMiddleware, SecurityHeadersMiddleware, HttpsRedirectMiddleware) .forRoutes({ path: '*', method: RequestMethod.ALL }); } } diff --git a/backend/src/middleware/csp-middleware/csp-middleware.ts b/backend/src/middleware/csp-middleware/csp.middleware.ts similarity index 94% rename from backend/src/middleware/csp-middleware/csp-middleware.ts rename to backend/src/middleware/csp-middleware/csp.middleware.ts index f9df509..b01790e 100644 --- a/backend/src/middleware/csp-middleware/csp-middleware.ts +++ b/backend/src/middleware/csp-middleware/csp.middleware.ts @@ -1,7 +1,6 @@ import { Injectable, NestMiddleware } from '@nestjs/common'; import { Request, Response, NextFunction } from 'express'; import { ConfigService } from '@nestjs/config'; -import { log } from 'console'; @Injectable() export class CspMiddleware implements NestMiddleware { diff --git a/backend/src/middleware/https-middlware/https-redirect.middleware.ts b/backend/src/middleware/https-middlware/https-redirect.middleware.ts new file mode 100644 index 0000000..59f0bb5 --- /dev/null +++ b/backend/src/middleware/https-middlware/https-redirect.middleware.ts @@ -0,0 +1,19 @@ +import { Injectable, NestMiddleware } from '@nestjs/common'; +import { ConfigService } from '@nestjs/config'; +import { NextFunction, Request, Response } from 'express'; + +@Injectable() +export class HttpsRedirectMiddleware implements NestMiddleware { + constructor(private configService: ConfigService) {} + + use(req: Request, res: Response, next: NextFunction) { + if (this.configService.get('NODE_ENV') === 'production') { + if (req.protocol === 'http') { + const httpsUrl = `https://${req.headers.host}${req.url}`; + res.redirect(httpsUrl); + } else { + next(); + } + } + } +} diff --git a/backend/src/middleware/security-middleware/security.middleware.ts b/backend/src/middleware/security-middleware/security.middleware.ts new file mode 100644 index 0000000..b766628 --- /dev/null +++ b/backend/src/middleware/security-middleware/security.middleware.ts @@ -0,0 +1,20 @@ +import { Injectable, NestMiddleware } from '@nestjs/common'; +import { Request, Response, NextFunction } from 'express'; +import { ConfigService } from '@nestjs/config'; + +@Injectable() +export class SecurityHeadersMiddleware implements NestMiddleware { + constructor(private configService: ConfigService) {} + + use(req: Request, res: Response, next: NextFunction): void { + if (this.configService.get('NODE_ENV') === 'production') { + res.setHeader( + 'Strict-Transport-Security', + 'max-age=63072000; includeSubDomains; preload' + ); + } + res.setHeader('X-Content-Type-Options', 'nosniff'); + res.setHeader('X-Frame-Options', 'SAMEORIGIN'); + next(); + } +}