Enhance Security for NodeJS Applications
Tags: typescript, node, express, beginners
Published: 2024-04-30 02:00:00

## 1. Limiting the number of requests 🎀🎀🎀

Limiting the number of requests (from a single IP address within a specific timeframe) is a method used to prevent denial-of-service (**DOS, DDOS**) attacks or brute force attacks that could overload your server.

![Limiting the number of requests](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/388cmn2hrnbcs83phwoa.png)

If you're using **Express**, integrating this is quite straightforward using the **express-rate-limit** package.

```ts
import * as express from 'express'
import helmet from 'helmet'
import expressRateLimit from 'express-rate-limit'

const app = express()
const limiter = expressRateLimit({
  windowMs: 10 * 60 * 1000, // ms, ~10 minutes
  max: 50, // limit each IP to 50 requests
})
const specificLimiter = expressRateLimit({
  windowMs: 60 * 60 * 1000, // 1 hour window
  max: 2, // start blocking after 2 requests
  message: 'Too many requests', // default 429 TOO MANY REQUESTS
})

app
  .use(limiter) // use for all route
  .use('/common', (req, res) => {
    res.json({api: 'common', ok: true})
  })
  .get('/specific-api', specificLimiter, (req, res) => { // use middleware for specific route
    res.json({api: 'specific', ok: true})
  })
  .listen(3000)
```

Note that if your development environment involves numerous test cases requiring requests to various APIs, it's advisable to exclude the rate limit. Always check the environment before starting the server to ensure that the rate limit is added in the production environment (or any desired environments).

## 2. Limiting the payload request size 🎀🎀🎀

Limiting the payload size sent to the server helps prevent **DOS/DDOS** attacks. Fortunately, Express also provides us with this capability as follows:

```ts
import * as express from 'express'

const app = express()
app
  .use(express.json({limit: '50kb'})) // body-parser defaults to a body size limit of 100kb
  .post('/send-data', (req, res) => {
    if (!req.is('json')) {
      return res.sendStatus(400) // Bad request
    }
    res.json({ok: true})
  })
  .listen(3000)
```

## 3. Using Helmet 📯📯📯

Helmet is an npm package that includes middleware to handle and filter out malicious request headers (exploiting XSS vulnerabilities or clickjacking, for example). You can utilize Helmet's default configuration or customize it based on your needs following the instructions provided [here](https://github.com/helmetjs/helmet).

![Using Helmet](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gbrfb2nl1el5vcvx7q9r.png)

Using it is as simple as:
```ts
import * as express from 'express'
import helmet from 'helmet'

const app = express()
app
  .use(helmet())
  .listen(3000)
```

## 4. Validate User Data Sent to the Server 📯📯📯

Even if data validation is performed solely on the frontend, it's crucial to validate it on the backend as well. Frontend validation primarily serves regular users, while hackers may exploit vulnerabilities like SQL Injection to directly attack the server. Check out the following [article for guidance on using express-validator to validate request data](https://medium.com/@hcach90/using-express-validator-for-data-validation-in-nodejs-6946afd9d67e). It's a simple yet effective solution to enhance your server's security.

![Validate User Data Sent to the Server](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/0l8ap9oumq98yos45o08.png)

## 5. Use ORM Libraries (Object-Relational Mapping) ⭐⭐⭐

Utilize packages like **TypeORM** or **Sequelize** to mitigate serious security risks like **SQL/NoSQL Injection**. These packages offer convenient and secure functions suitable for connecting to multiple databases or migrating to different databases without significantly altering logic. While there are debates about the impact of using these packages on system performance, you can enhance performance through various methods. Moreover, considering the security risks, prioritizing this aspect is essential.

Avoid concatenating strings when querying to prevent hidden security risks:
```ts
const idValue = req.id; // get id from request so that attackers can attach malicious code
const query = `SELECT * FROM table_name a WHERE a.id = ${idValue};`;
```

## 6. Avoid Storing Secret Info Directly in the Codebase ⭐⭐⭐

Sensitive information like **secret keys, database passwords, API keys**, and other crucial data should never be stored directly in the source code. Instead, place these details in a **.env** file (and remember to add the **.env** file to **.gitignore**). Here's a simple way to do it:

Install the dotenv package.
```sh
yarn add dotenv
```

Creating a .env file
```env
PASSWORD=password
```

Accessing Value
```ts
process.env.PASSWORD
```

Additionally, you can utilize **Key Management Service (KMS)** to store secret information on the cloud. Many providers like **AWS, GCP**, etc, offer support. Each method, whether using a **.env** file or **KMS**, has its pros and cons, so it's essential to weigh your options and choose what suits your needs best.

## 7. Choosing an Algorithm to Hash Passwords 🌱🌱🌱
Some hashing functions like **SHA1, MD5, SHA-256** have been around for a while, but their hash/second rate is low, making them unsuitable for password hashing. Instead, opt for algorithms with a high hash/second rate like **bcrypt** or **pbkdf2** to generate more complex hash strings. This will make it significantly more challenging and nearly impossible for attackers to crack passwords, as it will require a considerable amount of time and effort.

I'll provide a simple example using **bcrypt** to hash and compare passwords as follows:
```ts
import * as bcrypt from 'bcrypt'

const saltRounds = 10,
  password1 = 'password1',
  password2 = 'password2'

// 2 ways to gen hash
const hash1: string = await new Promise(rs =>
  bcrypt.genSalt(saltRounds, (err, salt) => {
    bcrypt.hash(password1, salt, (err, hash) => {
      rs(hash) // store hash in your password DB.
    })
  })
)
const hash2 = await bcrypt.hash(password2, saltRounds)

// load hash from your password DB to compare
bcrypt.compare(password1, hash1, (err, result) => {
  console.log(password1, hash1, result)
})
const result = await bcrypt.compare(password2, hash2)
console.log(password2, hash2, result)
```

## 8. Using HTTPS 🌱🌱🌱

When you use **HTTP (Hypertext Transfer Protocol)**, data sent to the server isn't encrypted and can be intercepted and read by hackers. Nowadays, browsers like Chrome, Firefox, etc., display warnings when you access websites using HTTP. This can diminish your website's credibility to users and affect its ranking on search engines.

Using **HTTPS (HTTP Secure)** means that data sent to the server is encrypted, making it difficult for attackers to exploit sensitive information from those requests. However, it's important to note that accessing a website with **HTTPS** doesn't guarantee complete security.

![Using HTTPS](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d983k1q0nnnupplngc0o.png)

To implement **HTTPS** for your website quickly and easily, you can use **Cloudflare**. It's a popular third-party service that acts as a proxy between users and your server, providing support for certificates and encryption. Simply sign up for a free **Cloudflare** account and configure details like your IP address and domain name. Since it's a third-party service, access speed may be slightly slower than usual.

## Conclusion 🏆🏆🏆
Through this article, you've learned some methods to enhance security for your **NodeJS** application. These methods are relatively straightforward and can be implemented right away in your current project.

**_Don't hesitate to leave your thoughts in the comments section, and remember to like, share, and follow for more insightful content in the future!_**🙏🙏

**_If you found this content helpful, please visit [the original article on my blog](https://howtodevez.blogspot.com/2024/04/enhance-security-for-nodejs-applications.html) to support the author and explore more interesting content._**🙏🙏

<a href="https://howtodevez.blogspot.com/2024/03/sitemap.html" target="_blank" rel="noreferrer"><img src="https://img.shields.io/badge/Blogger-FF5722?style=for-the-badge&logo=blogger&logoColor=white" width="36" height="36" alt="Blogspot" /></a><a href="https://dev.to/chauhoangminhnguyen" target="_blank" rel="noreferrer"><img src="https://img.shields.io/badge/dev.to-0A0A0A?style=for-the-badge&logo=dev.to&logoColor=white" width="36" height="36" alt="Dev.to" /></a><a href="https://www.facebook.com/profile.php?id=61557154776384" target="_blank" rel="noreferrer"><img src="https://img.shields.io/badge/Facebook-1877F2?style=for-the-badge&logo=facebook&logoColor=white" width="36" height="36" alt="Facebook" /></a><a href="https://x.com/DavidNguyenSE" target="_blank" rel="noreferrer"><img src="https://img.shields.io/badge/X-000000?style=for-the-badge&logo=x&logoColor=white" width="36" height="36" alt="X" /></a>