Table of contents
Attackers are always looking for vulnerabilities to exploit and get access to things they shouldn't. Building secure web applications is very important and should be a priority in your development.
Prerequisites
To get started and have a better understanding of the article, you need basic knowledge of the following technologies.
Javascript
Backend development
Nodejs
Express
Expressjs is a very popular unopinionated Nodejs framework for developing web applications and offers many awesome features for easier and faster development.
However, because it has no specified way of building your applications i.e. gives the developer full control of architecting the application how they like/ prefer, the programmer decides on tools/ libraries they are going to use and adds only what they need. And because of this, security does not come out of the box like in other frameworks to prevent common vulnerabilities.
Luckily, you can add tools such as helmet as middlewares to safeguard your application from common vulnerabilities such as cross-site scripting, and click-jacking attacks and reduce server fingerprinting("exposing your tech stack").
Well, how does that work and what is helmet? helmet is an open-source javascript library that is designed to secure your Nodejs application by setting several HTTP headers to comply with web security standards.
To understand how helmet works, we are going to build a small express server. To get started, make sure you have Nodejs downloaded, if not, you can get it from Nodejs official website and install it on your PC. Confirm that everything is working by opening the command prompt ('on Windows) or terminal and type node -v
and this should give you the version of Nodejs installed as follows.
Now, that we have Nodejs, let's build our application. First, navigate to the directory you want to set up your project. For easy deployment, as we'll be using a live version to analyze for security issues, you can create a repository on GitHub, adding gitignore with Nodejs template, adding license and Readme file, and then cloning the repo into your local machine.
Setting up Express server
In this tutorial, we are going to set up a simple server so we don't have to think about architecture and file structure, we are going to have a single file, server.js
. In the directory that we're working on, let's initialize package.json by using npm init -y
We can now start by adding dependencies to our project, and in this case, let us start by just adding our main dependency, Express js, we are using npm as our package manager. To add express, use npm install express
or npm i express
which does the same thing. This will generate a node_modules folder with everything Express needs to run.
With Express installed, let us set up our server. Create a file server.js and add the following code using your favorite IDE, mine is VSCode.
// server.js
const express = require('express');
const PORT = process.env.PORT || 5000
// initializing app instance
const app = express();
//basic API that returns 'hello world'
app.get("/", (req,res)=>{
res.json("Hello world")
}
);
app.listen(PORT, ()=>{
console.log(`Server running on port ${PORT}`);
}
start the server running node server.js
in the terminal and if you see as follows, congrats, you have a running express server!
Now, let us explore default express behaviors without helmet, we are going to use curl
command but alternatively, you can use tools like Postman. to use curl
. run curl http://localhost:5000 --include
, include
flag will add HTTP headers to the response object and you'll get the following response,
You can notice that it has an X-powered-By header which is a non-standard header generated by many frameworks and this will let attackers know the web stack/ technology used in your website and they can use this to exploit your application through known vulnerabilities in the framework or library.
We are going to use security headers to analyze the security of our application and to do this, we need a publicly available address. We can do this by hosting our application on services like Render which will be free. I have my code hosted in GitHub which will be easy to deploy. After logging into your render account, add web service, select the repository, and follow the instructions to deploy.
Here is the live link to my deployed web server. Now, we can go ahead and analyze the security of the application without helmet using security headers.
After clicking scan, you can see an F grade and a message, "Ouch, you should work on your security posture immediately"
Now, let's explore how helmet will help us secure our application.
Using Helmet
First, we need to install hemet, use
npm i helmet
or npm install helmet
After successful installation, we need to use helmet in our application, to do this we are going to require helmet by adding the following line of code,
const helmet = require('helmet');
Helmet is incorporated into our application as a middleware, to register middleware in express, we use app.use(middlewareName)
, and in the case of helmet, we are going to use
app.use(helmet());
your final server.js file should look like this
// server.js
const express = require('express');
const PORT = process.env.PORT || 5000
const helmet = require('helmet')
// initializing app instance
const app = express();
//middlewares
app.use(helmet());
//basic API that returns 'hello world'
app.get("/", (req,res)=>{
res.json("Hello world")
}
);
app.listen(PORT, ()=>{
console.log(`Server running on port ${PORT}`);
});
Now, commit your changes, and render should redeploy automatically with the latest commit to reflect the changes automatically. Now, let us re-analyze our application again using security headers.
And, Tada!, we have grade A, more secure applications by adding only two lines of code. Now let us see what helmet does under the hood.
Helmet function actually is a wrapper to 15 sub-middlewares that each takes care of setting up one HTTP security header so by using helmet
middleware, you are adding 15 express middleware into your app.
Let us explore what each security header does and how it is configured default by helmet so that you can modify it according to your needs.
Content-security-policy header helps to prevent several attacks such as cross-site scripting and code injection. It allows you to specify the type of content your webpage is allowed to load and execute. To configure this header, pass an Object with a nested directive object. Here is an example from Helemt's official documentation.
// This sets custom options for the
// Content-Security-Policy header.
app.use(
helmet({
contentSecurityPolicy: {
directives: {
"script-src": ["'self'", "example.com"],
},
},
})
);
You can read much about the security headers and how to configure them on the official docs here. Happy coding