The initial Node.js release happened a little bit more than 8 years ago. Since then Node.js became one of the leading platforms for building backend applications. As such, security becomes more and more important.
In the first part of this article you will learn where Node.js and npm are when it comes to security. In the second part, you will learn some best security practices which you can immediately apply to your Node.js applications.
As a Node.js developer, you most probably work with a huge amount of user data - some of them being very sensitive in nature. Businesses built in the cloud-native era should always treat their data in the top-most respect.
As the saying goes - your attackers need to get things right only once, while you as an application developer has to be right all the time.
One of the best examples of this is the website called have i been pwned? operated by Troy Hunt, which collects security breaches, and makes publicly available breaches searchable, so you can know if one of your accounts may got exploited π₯. Breached websites include LinkedIn, Adobe or MySpace, just to name the bigger ones.
But what about Node.js?
As of today, Node.js and its core contributors maintain many different channels to address the security of the Node.js project and the security of its' users.
In 2016, at Node.js Interactive in Austin, the Security Working Group was formed, addressing the need for a working group focusing on security. It is mainly responsible for defining and maintaining security policies and procedures for the core Node.js project and other projects maintained by the Node.js Foundation.
The Security Working Group also helps with:
For more information, check out the Security working group GitHub repository.
If you feel like you found a security bug in Node.js, you should report it to security@node.js.org. Once you do that, your email will be acknowledged within 24 hours and if needed, the security team may ask you for more details in the next 48 hours.
To better understand the process, and read the full disclosure policy, check out the official Node.js security page.
npm is by far the biggest package ecosystem in the world, with more than half a million packages, growing with 500 new modules daily. We download these packages more than 3 billion times every week. At this scale, the security is the ecosystem is of the top-most priorities.
As the responsible maintainer and developer of the registry, npm, make important steps towards making npm more secure every step down the road, like:
β οΈ Before you continue reading the article, take a minute to enable Two-Factor Authentication for your npm account now. β οΈ
Even if npm does everything in its power to secure the registry, it can still happen that modules have security vulnerabilities. As most applications can easily end up depending on hundreds if not thousands of modules, auditing each one of them before you start using them is not something you have the time to do.
Luckily, the Node.js Security Project, as well as Snyk maintains security advisories, with both companies offering paid subscription plans to run their tools in CI/CD environments:
It is time to get hands on, and make your application more secure! If you follow and implement the next items carefully, you are already making great progress towards a more secure Node.js application.
Helmet helps you secure your Express applications by setting various HTTP headers, like:
Helmet supports a lot more headers, to get the full list, visit the official documentation of helmet.
Adding helmet
to your applications is just a few lines of codes away:
const express = require("express");const helmet = require("helmet");const app = express();app.use(helmet());
Validating user input is one of the most important things to do when it comes to the security of your application. Failing to do it correctly can open up your application and users to a wide range of attacks, including command injection, SQL injection or stored cross-site scripting.
To validate user input, one of the best libraries you can pick is joi. Joi is an object schema description language and validator for JavaScript objects. To get an idea what it can do for you, take a look at the following example:
const Joi = require("joi");const schema = Joi.object().keys({username: Joi.string().alphanum().min(3).max(30).required(),password: Joi.string().regex(/^[a-zA-Z0-9]{3,30}$/),access_token: [Joi.string(), Joi.number()],birthyear: Joi.number().integer().min(1900).max(2013),email: Joi.string().email(),}).with("username", "birthyear").without("password", "access_token");// Return resultconst result = Joi.validate({username: "abc",birthyear: 1994,},schema);// result.error === null -> valid
When it comes to validating user input passed into SQL queries, you should always escape any user provided data before using it in a SQL query in combination with validating user input. If you are using the mysql
module, it looks something like this:
connection.query("UPDATE users SET foo = ?, bar = ?, baz = ? WHERE id = ?",["a", "b", "c", userId],function (error, results, fields) {// ...});
If you are using an ORM like sequelize, it comes with the concept of Prepared Statements (also sometimes referred as Parameterized Statements too). Just like the mysql
module, it understands ?
and will encode it properly.
Regular Expressions are a great way to manipulate texts and get the parts that you need from them. However, there is an attack vector called Regular Expression Denial of Service attack, which exposes the fact that most Regular Expression implementations may reach extreme situations for specially crafted input, that cause them to work extremely slowly.
Combined with the fact that Node.js is single-threaded by nature, with a single user input a whole server can be taken down. The Regular Expressions that can do such a thing are commonly referred as Evil Regexes. These expressions contain:
Examples of Evil Regular Expressions patterns:
(a+)+
([a-zA-Z]+)*
(a|aa)+
A potential input that can cause the first regular expression to run very slowly is aaaaaaaaaaaaaaaaaaaaaaaaX
.
To detect these regular expressions, you can use the safe-regex module.
Security.txt defines a standard to help organizations define the process for security researchers to securely disclose security vulnerabilities. Currently, it is in a draft stage, with the following intended purpose:
When security risks in web services are discovered by independent security researchers who understand the severity of the risk, they often lack the channels to properly disclose them. As a result, security issues may be left unreported. Security.txt defines a standard to help organizations define the process for security researchers to securely disclose security vulnerabilities. - from the security.txt draft
In case you'd like to add it to your application to help researchers report security bugs to you, I've just published a Node.js module that makes it super easy, called express-security.txt. Adding it to your app is as easy as:
const express = require("express");const securityTxt = require("express-security.txt");const app = express();app.get("/security.txt",securityTxt({// your security addresscontact: "email@example.com",// your pgp keyencryption: "encryption",// if you have a hall of fame for securty resourcers, include the link hereacknowledgements: "http://acknowledgements.example.com",}));