Top 10 Node.js Security Best Practices
Clear Gate | Cyber Security & Research
In-Depth, Manual Penetration Tests
Written By Sagiv Michael, Penetration Tester at Clear Gate Cyber Security and Research
This article is also available on our blog: https://www.clear-gate.com/blog/top-10-node-js-security-best-practices/
Introduction
Node.js is an open-source, cross-platform JavaScript runtime environment built on Chrome’s V8 JavaScript engine. It allows developers to execute JavaScript code outside a web browser, making it an excellent choice for server-side and network applications. With its event-driven, non-blocking I/O model, Node.js enables efficient handling of concurrent connections and scalability, making it highly suitable for building real-time and data-intensive applications.
Express.js, commonly known as Express, is a popular and minimalist web application framework for Node.js. It provides robust features and tools to build web applications and APIs quickly and efficiently. Express.js is widely used in the Node.js community due to its simplicity, flexibility, and ease of use. It acts as a middleware to handle requests and responses, making it a fundamental part of many Node.js applications.
This article will discuss ten of the best security practices for Node.js and Express.js and how to apply them in your web application. These security practices are organized in descending order from highest to lowest risks.
1. Mitigating Cross-Site Scripting (XSS) Attacks
Cross-site scripting (XSS) is a security vulnerability that allows attackers to inject arbitrary JavaScript code into web pages viewed by other users and perform malicious actions. To prevent XSS attacks, it is essential to properly encode user-generated content before displaying it in HTML templates.
For this purpose, the Pug package can be used. Pug, formerly known as Jade, is a high-performance and feature-rich template engine for Node.js. It allows you to write reusable HTML and includes powerful features for layout and templating.
One of the key features of Pug, as it relates to security, is that it automatically encodes output, which helps to mitigate Cross-Site Scripting (XSS) attacks.
To install the “pug” package, execute the following command:
npm install pug
2. Mitigating NoSQL Injection Attacks
Unlike SQL injection, NoSQL injection attacks target NoSQL databases used in web applications. To protect against NoSQL injection, utilize parameterized queries or Object Data Modeling (ODM) libraries that automatically handle escaping and sanitization.
Mongoose is a MongoDB object modeling tool designed to work in an asynchronous environment. It provides a straightforward, schema-based solution to model the application data, including built-in type casting, validation, query building, and business logic hooks. In other words, Mongoose is an Object Data Modeling (ODM) library for MongoDB and Node.js. It manages relationships between data, provides schema validation, and is used to translate between objects in code and the representation of those objects in MongoDB.
To install the “mongoose” package, execute the following command:
npm install mongoose
3. Mitigating Cross-Site Request Forgery (CSRF) Attacks
CSRF attacks trick authenticated users into unknowingly executing malicious actions on a web application.
A common approach to mitigate CSRF attacks involves using a CSRF token, a random value generated for each form or session, which is then validated with each request. The server only processes the request if the CSRF token is valid. Because the CSRF token is specific to each user and each session, an attacker can’t simply guess the value of the CSRF token, which makes CSRF attacks much more difficult.
In Node.js, the “csrf” middleware package provides easy-to-use protection against CSRF attacks.?
To install the “csrf” package, execute the following command:
npm install csrf
4. Validating User Input
Server-side development must always involve strict user input validation to prevent potential issues, such as SQLi and XSS. One way to achieve this is by using the “Ajv” validator, which is a fast JSON Schema validator for Node.js.
Example code using “Ajv” validator:
In this example, the schema defines a JSON schema that requires an object with a name (a string) and age (an integer). The name field is required, but the age field is optional. The validate function is a compiled function from the schema that can be used to validate data. If the data is invalid, validate(data) will return false, and validate.errors will contain an array of error objects describing the validation errors.
A JSON schema validator like “Ajv” can add an extra layer of security to the application by ensuring incoming data conforms to a specified format before processing occurs. This can help protect against several potential security vulnerabilities:
To install the “ajv” package, execute the following command:
npm install ajv
5. Controlling User Access with JWT
JSON Web Tokens (JWT) are widely used to transfer authentication data in client-server applications. When using JWT, it is essential to control user access based on specific permissions or roles. For this purpose, you can leverage the “express-jwt-permissions” package along with “express-jwt”, which is the most used middleware package in Node.js for deploying and validating JWTs.”
To install the “express-jwt-permissions” package, execute the following command:
npm install express-jwt-permissions
6. Protecting Against Brute Force Attacks
The term “brute force” refers to attempting every possible combination until one works. It essentially uses “brute” computational power to force unauthorized access to a system.
For example, if an attacker is trying to crack a four-digit PIN, the attacker might start with “0000”, then try “0001”, “0002”, and so on, all the way up to “9999”.
Brute force attacks can be time-consuming and resource-intensive. The more complex the password or encryption key (i.e., the longer it is, the more types of characters it includes), the more potential combinations there are to try, and the longer a brute force attack will take.
领英推荐
To mitigate this risk is required to implement a rate-limiting protection mechanism using the “rate-limiter-flexible” package. This package works well with any Node.js framework and allows control of the number of requests sent per time frame from a particular IP address.
To install “rate-limiter-flexible,” execute the following command:
npm install rate-limiter-flexible
Alternatively, the “express-rate-limit” package can be used for simpler rate-limiting implementations. This package is more straightforward because it has fewer configuration options and no need to explicitly consume points or handle rejections as with rate-limiter-flexible.?
To install “express-rate-limit” execute the following command:
npm install express-rate-limit
7. Securing Your Cookies
In Express.js version 4, cookies can be managed using two built-in modules in Express.js: “express-session” and “cookie-session.”
The “cookie-session” stores session data directly in cookies, unlike “express-session” which stores the session ID in the cookie and the session data on the server.
For efficient cookie handling, “cookie-session” is generally preferred because it stores the session data directly in a cookie sent to the client. When the client makes subsequent requests, the session data is sent directly to the server in the cookie, eliminating the need for a round trip to a session store to retrieve the session data from the server. However, if complex session data should be stored (cookie-session is limited to 4KB) or ensure that the data remains hidden from the client, “express-session” is a better choice.
When setting cookie security attributes, using the following properties is a best practice:
8. Ensuring Secure Connections and Data Communication Transfer
Securing your application’s connections and data communication transfer is essential. To achieve this, you can rely on Helmet.js? from the Node.js modules, which provides 13 middleware functions to set necessary HTTP response headers. These headers include Content Security Policy, handling Certificate Transparency, preventing clickjacking, turning off client-side caching, and mitigating XSS attacks.
To begin with, set the “HSTS (HTTP-Strict-Transport-Security)” header. HSTS is a web security policy mechanism that helps to protect websites against protocol downgrade attacks and cookie hijacking. It allows web servers to declare that web browsers (or other complying user agents) should only interact with it using secure HTTPS connections and never allow communication via the insecure HTTP protocol.
To install the Helmet.js package, execute the following command:
npm install hpp
9. Ensuring Secure Software Dependencies
When working with npm (node package manager) for web development, using the latest secure version of the software dependencies is vital to avoid potential vulnerabilities that may compromise the application. Regularly perform dependency checks using a dedicated command to identify and fix security issues in your project’s dependencies.
To analyze the tree of dependencies, you can execute the following command:
npm audit
10. Using an Updated Version of Express.js
When developing an Express.js application, it is crucial to use up-to-date and supported versions. Versions 2 and 3 of Express are deprecated and no longer receive security or performance updates.
To ensure the best development experience, switch to Express.js version 4. This version (according to the time of writing this article) brings a significant evolution, introducing improvements in the routing system, middleware handling, and other essential aspects.
To achieve automatic updates for all Node.js packages in your system, you can set up a weekly cron job on Linux or a scheduled task on Windows. For instance, to schedule a weekly task in Linux, you can follow the example below:
An example of scheduling a task every week using Linux:
0 0 0 npm update -g
This cron expression breaks down as follows:
0: Minute (0-59)
0: Hour (0-23)
*: Day of the month (1-31)
*: Month (1-12)
0: Day of the week (0-7, where both 0 and 7 represent Sunday)
Conclusion
Ensure a secure web application with Node.js and Express by using the latest version, securing connections and data, safeguarding cookies, updating dependencies, validating user input, defending against brute force attacks, and controlling user access with JWT.?
Organizations should prioritize cyber security risk assessments and penetration tests to mitigate risks in developing Node.js applications, which have become increasingly popular among companies developing SaaS products. Clear Gate, a trusted cybersecurity provider, offers in-depth manual penetration tests to help organizations strengthen their web application security and protect valuable data from potential threats.
References