When you ride a bike you need a helmet, but what about when developing backend applications? Today we'll talk about how we can use Helmet in a NestJS application to secure it and make sure our users won't get an 'ouchie'.
Before we dive into the intricacies of NestJS Helmet, let's take a moment to recognize the increasing importance of securing our backend applications. One of my colleagues kept saying that what's made by a dev can be broken by another so nothing is safe. Security breaches can have severe consequences, from compromising sensitive user data to damaging the reputation of your application and brand. I hope I don't need to explain the value of robust security measures in today's tech environment.
What is Helmet?
Helmet is a middleware specifically designed to enhance the security of NestJS applications by setting various HTTP headers. These headers, when configured properly, act as a shield against common web vulnerabilities, providing an added layer of protection to your backend.
Let's talk about some of the most pressing security issues
Cross-site scripting (XSS) - This type of attack usually appears when a developer fails to adequately validate user input. In this scenario, an attacker can inject modified JavaScript code into the web pages that users are viewing. Because the browser can't determine if the code is safe or not to run, it will run the code by default which could give the attacker access to sensitive information like cookies, tokens, user information or even more. Helmet helps you implement CSP, preventing unauthorized execution of scripts and protecting your application from Cross-Site Scripting (XSS) attacks.
Strict-Transport-Security (HSTS) - By enforcing the use of HTTPS, Helmet safeguards your application from man-in-the-middle attacks, ensuring a secure communication channel between the client and server.
X-Frame-Options - Protect your application from clickjacking attacks by using Helmet to set the appropriate X-Frame-Options header.
Let's put our Helmet on
We can install Helmet through npm. In this first example, I will consider you are using Express.js:
npm install --save helmet
After we install the package we can use it by applying Helmet as a global middleware. This can be done in the main.ts file:
import helmet from 'helmet';
// code
// more code
// even more code
app.use(helmet());
But Paul, I don't need all the things that helmet offers, can I just use parts of it without actually setting up everything by default? Yes, of course, you can use only parts of what Helmet has to offer. The snippet below shows how you can use Helmet features with default configs.
import helmet from "helmet";
// ...
app.use(helmet.contentSecurityPolicy());
app.use(helmet.crossOriginEmbedderPolicy());
app.use(helmet.crossOriginOpenerPolicy());
app.use(helmet.crossOriginResourcePolicy());
app.use(helmet.dnsPrefetchControl());
app.use(helmet.frameguard());
app.use(helmet.hidePoweredBy());
app.use(helmet.hsts());
app.use(helmet.ieNoOpen());
app.use(helmet.noSniff());
app.use(helmet.originAgentCluster());
app.use(helmet.permittedCrossDomainPolicies());
app.use(helmet.referrerPolicy());
app.use(helmet.xssFilter());
Can I use it with Fastify?
Of course, you can check the snippets below:
npm install --save @fastify/helmet
You can use it similar to the Express one:
import helmet from '@fastify/helmet';
// code
// more code
// even more code
await app.register(helmet);
Let's get practical
Let's get into some ways you can configure Helmet in your NestJS app:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as helmet from 'helmet';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", 'boreditguy.com'],
styleSrc: ['boreditguy.com'],
},
},
}));
await app.listen(3000);
}
bootstrap();
Other simple examples:
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import * as helmet from 'helmet';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
app.use(
helmet({
hidePoweredBy: { setTo: 'PHP 7.4.3' },
frameguard: { action: 'deny' },
xssFilter: true,
noSniff: true,
})
);
await app.listen(3000);
}
bootstrap();
A secure Nest is a happy Nest
After writing this article, one thing crossed my mind: remember that the digital landscape is dynamic, and security is an ongoing process. By adopting best practices and leveraging tools like Helmet, you're not just building applications – you're fortifying digital fortresses. If you have any doubts, don't forget to check the official NestJS documentation by clicking here.
If you want to read other NestJS-related articles that I wrote, check it out here.
Happy Coding!