Sling Academy
Home/Node.js/CSRF Protection in NestJS: How to Implement It

CSRF Protection in NestJS: How to Implement It

Last updated: December 31, 2023

Securing web applications is crucial, and CSRF (Cross-Site Request Forgery) protection is fundamental in a NestJS application. This tutorial will guide you through implementing robust CSRF protection leveraging NestJS’s latest features and TypeScript.

Introduction

CSRF attacks involve tricking a user into sending unauthorized commands to a web application where they’re authenticated. In a NestJS application, CSRF protection can be effectively implemented using CSRF tokens that validate user requests. NestJS offers built-in CSRF protection that integrates seamlessly with Express or Fastify. In this tutorial, we’ll be working with the Express platform.

Setting Up the NestJS Project

npm i -g @nestjs/cli
nestjs new my-csrf-secure-app

After setting up the project, navigate to it:

cd my-csrf-secure-app

Integrating CSRF Middleware

First, let’s integrate the CSRF middleware by installing the required package:

npm i csurf

Within your application, set up CSRF protection by applying it as global middleware.

import * as csurf from 'csurf';

// main.ts
async function bootstrap() {
  const app = await NestFactory.create(AppModule);
  app.use(csurf());
  await app.listen(3000);
}
bootstrap();

Note that CSURF middleware requires either a session middleware or cookie-parser to read cookies, which you’ll need to install and set up accordingly.

Handling CSRF Tokens

The next step is to generate a CSRF token and provide it to the client. This is usually done by including the token in the rendered views.

import { Controller, Get, Req, Res } from '@nestjs/common';
import { Request, Response } from 'express';

@Controller()
export class AppController {
  @Get()
  provideCsrfToken(@Req() request: Request, @Res() response: Response) {
    response.render('form', { csrfToken: request.csrfToken() });
  }
}

Including CSRF Tokens in Client Requests

When submitting forms or sending AJAX requests, ensure the CSRF token is included. An example using a template engine form:

<form action="/submit" method="post">
    <input type="hidden" name="_csrf" value="{{csrfToken}}">
    <!-- form fields -->
    <button type="submit">Submit</button>
</form>

In AJAX requests:

fetch('/submit', {
  method: 'POST',
  headers: {'Content-Type': 'application/json', 'CSRF-Token': 'your-csrf-token'},
  body: JSON.stringify({data: 'your-data'})
});

Advanced Configuration and Strategies

In more advanced scenarios, you might want to customize the CSRF implementation. You can configure the CSURF options directly to control aspects like the cookie settings or the response on token validation failure.

app.use(csurf({cookie: {httpOnly: true, secure: process.env.NODE_ENV === 'production'}}));

For RESTful APIs that serve client applications separately (e.g., Single Page Applications), you’ll need to devise CORS and CSRF protection strategies that ensure both are correctly handled.

Testing CSRF Protection

Ensure your CSRF protection is effective by writing tests that aim to simulate CSRF attacks, either manually or using testing libraries.

import { Test } from '@nestjs/testing';
import * as request from 'supertest';
import { AppModule } from './../src/app.module';

describe('CSRF Protection', () => {
  it('should prevent unprotected POST request', () => {
    const moduleFixture = await Test.createTestingModule({
      imports: [AppModule],
    }).compile();

    const app = moduleFixture.createNestApplication();
    await app.init();

    return request(app.getHttpServer())
      .post('/submit')
      .expect(403); // Expects a Forbidden error
  });
});

Conclusion

Incorporating CSRF protection into your NestJS applications is straightforward with the built-in middleware and strategies provided by the framework. By following the steps in this tutorial, you can ensure that your application validates requests properly, keeping user data secure from CSRF vulnerabilities.

Next Article: Mastering NestJS CLI: A Practical Guide

Previous Article: How to Implement Rate Limiting in NestJS

Series: Nest.js Tutorials: From Basics to Advanced

Node.js

You May Also Like

  • NestJS: How to create cursor-based pagination (2 examples)
  • Cursor-Based Pagination in SequelizeJS: Practical Examples
  • MongooseJS: Cursor-Based Pagination Examples
  • Node.js: How to get location from IP address (3 approaches)
  • SequelizeJS: How to reset auto-increment ID after deleting records
  • SequelizeJS: Grouping Results by Multiple Columns
  • NestJS: Using Faker.js to populate database (for testing)
  • NodeJS: Search and download images by keyword from Unsplash API
  • NestJS: Generate N random users using Faker.js
  • Sequelize Upsert: How to insert or update a record in one query
  • NodeJS: Declaring types when using dotenv with TypeScript
  • Using ExpressJS and Multer with TypeScript
  • NodeJS: Link to static assets (JS, CSS) in Pug templates
  • NodeJS: How to use mixins in Pug templates
  • NodeJS: Displaying images and links in Pug templates
  • ExpressJS + Pug: How to use loops to render array data
  • ExpressJS: Using MORGAN to Log HTTP Requests
  • NodeJS: Using express-fileupload to simply upload files
  • ExpressJS: How to render JSON in Pug templates