DEV Community

Cover image for ๐Ÿ”’ Node.js Security Best Practices
ROHIT SINGH
ROHIT SINGH

Posted on

๐Ÿ”’ Node.js Security Best Practices

When building modern applications with Node.js, security is not optional โ€” itโ€™s essential. As your APIs and microservices grow, so does the attack surface. A small misconfiguration or missing validation can expose sensitive data, invite brute-force attacks, or even bring down your entire system.

In this blog, weโ€™ll walk through the most important Node.js security best practices with practical examples you can apply right away.

  1. Validate and Sanitize Input

Never trust user input. Attackers often try SQL Injection, NoSQL Injection, or XSS using cleverly crafted payloads.

import validator from "validator";

app.post("/register", (req, res) => {
  const { email } = req.body;

  if (!validator.isEmail(email)) {
    return res.status(400).send("Invalid email format");
  }

  res.send("User registered");
});
Enter fullscreen mode Exit fullscreen mode

๐Ÿ‘‰ Always validate data before processing.

  1. Secure HTTP Headers with Helmet

By default, Node apps donโ€™t include security headers. Use Helmet to add protections like Content-Security-Policy, XSS-Protection, and Strict-Transport-Security.

import helmet from "helmet";
app.use(helmet());
Enter fullscreen mode Exit fullscreen mode
  1. Prevent NoSQL Injection

If youโ€™re using MongoDB, attackers can inject queries like { "$gt": "" } to bypass filters.

import mongoSanitize from "express-mongo-sanitize";
app.use(mongoSanitize());
Enter fullscreen mode Exit fullscreen mode
  1. Apply Rate Limiting (Stop Brute-Force)

Attackers often hammer login endpoints. Prevent this with rate limiting.

import rateLimit from "express-rate-limit";

const limiter = rateLimit({
  windowMs: 15 * 60 * 1000,
  max: 100
});

app.use("/api/", limiter);
Enter fullscreen mode Exit fullscreen mode
  1. Enforce HTTPS

Always redirect traffic to HTTPS to protect data in transit.

app.use((req, res, next) => {
  if (req.headers["x-forwarded-proto"] !== "https") {
    return res.redirect("https://" + req.headers.host + req.url);
  }
  next();
});

Enter fullscreen mode Exit fullscreen mode
  1. Manage Secrets Safely

Never hardcode secrets in your codebase. Use environment variables or secret managers.

import dotenv from "dotenv";
dotenv.config();

const jwtSecret = process.env.JWT_SECRET;
Enter fullscreen mode Exit fullscreen mode
  1. Hash Passwords Before Storing

Storing plain-text passwords is a critical mistake. Always hash them with bcrypt.

import bcrypt from "bcrypt";

const hashPassword = async (password) => {
  const salt = await bcrypt.genSalt(12);
  return await bcrypt.hash(password, salt);
};
Enter fullscreen mode Exit fullscreen mode
  1. Update Dependencies Regularly

Outdated packages may contain vulnerabilities. Run:

npm audit fix
Enter fullscreen mode Exit fullscreen mode

and consider tools like Snyk for continuous monitoring.

  1. Configure CORS Properly

Allow requests only from trusted origins.

import cors from "cors";

app.use(cors({
  origin: ["https://myapp.com"],
  methods: ["GET", "POST"]
}));
Enter fullscreen mode Exit fullscreen mode
  1. Protect Against CSRF Attacks

For state-changing requests, implement CSRF protection.

import csurf from "csurf";
app.use(csurf());
Enter fullscreen mode Exit fullscreen mode
  1. Donโ€™t Leak Error Details

Verbose error messages can expose internal logic. Show generic messages in production.

app.use((err, req, res, next) => {
  console.error(err.stack); // log internally
  res.status(500).send("Something went wrong!");
});
Enter fullscreen mode Exit fullscreen mode
  1. Run Node with Least Privileges

Avoid running Node apps as root. Use Docker non-root users or pm2 with restricted permissions.

  1. Content Security Policy (CSP)

CSP helps control what external scripts or styles your app can load โ€” mitigating XSS risks.

app.use(
  helmet.contentSecurityPolicy({
    directives: {
      defaultSrc: ["'self'"],
      scriptSrc: ["'self'", "trustedscripts.com"]
    }
  })
);
Enter fullscreen mode Exit fullscreen mode

โœ… Quick Security Checklist

Validate and sanitize input

Secure headers with Helmet

Prevent NoSQL/SQL injections

Apply rate limiting

Enforce HTTPS

Securely store secrets

Hash passwords with bcrypt

Enable CORS and CSRF protection

Donโ€™t leak stack traces in production

Run apps with least privileges

Keep dependencies updated

๐Ÿš€ Final Thoughts

Securing a Node.js application is an ongoing process, not a one-time task. Start by applying these best practices, then continuously monitor your app for new threats. Remember: a single weak point can compromise the entire system.

By following these steps, youโ€™ll build robust, production-ready Node.js applications that can stand against real-world attacks.

๐Ÿš€ Rohit Singh ๐Ÿš€ โ€“ Medium

Read writing from ๐Ÿš€ Rohit Singh ๐Ÿš€ on Medium. Full-stack developer with 6+ years in Angular, Node.js & AWS. Sharing tips, best practices & real-world lessons from building scalable apps.

favicon medium.com

Top comments (0)