Securing Node.js Applications
Backend Security Best Practices: A Comprehensive Guide

NITian | Full Stack Web Developer | DevOps Enthusiast
Search for a command to run...
Backend Security Best Practices: A Comprehensive Guide

NITian | Full Stack Web Developer | DevOps Enthusiast
No comments yet. Be the first to comment.
As developers, ensuring the security of our applications is paramount. In the world of backend development with Node.js, several key practices and tools can significantly enhance the security of your application. Let's dive into a comprehensive guide covering the essential backend security best practices.
The foundation of any secure application starts with the packages it depends on. Regularly audit and fix vulnerabilities using the following commands for Yarn and NPM:
For Yarn:
yarn audit
yarn audit fix
For NPM:
npm audit
npm audit fix
Cross-Origin Resource Sharing (CORS) is vital for controlling which origins can access your Node.js application's resources. Implement CORS using the following code snippet:
const whitelist = ["http://localhost:3000"];
const corsOptions = {
origin: function (origin, callback) {
if (whitelist.indexOf(origin) !== -1) {
callback(null, true);
} else {
callback(new Error("Not allowed by CORS"));
}
},
};
app.use(cors(corsOptions));
Helmet.js is an Express middleware that helps set various HTTP headers for enhanced security. Integrate it into your application with the following line:
app.use(helmet());
Protect your application from abuse and excessive requests with rate limiting. Define a limiter middleware, allowing exceptions for specific IPs:
const allowlist = ["192.168.0.56", "192.168.0.21"]
const limiter = rateLimit({
windowMs: 60 * 1000, // 1 minute
max: 50, // 50 requests per IP
message: "Too many requests from this IP, please try again after 1 minute!",
skip: (req, res) => allowlist.includes(req.ip),
});
app.use(limiter);
Implement a request size limit to prevent excessively large payloads that could lead to server issues or DoS attacks:
app.use(express.json({ limit: '10kb' }));
It is an attack in which attackers send multiple HTTP parameters with the same name and this causes your application to interpret them unpredictably. When multiple parameter values are sent, Express populates them in an array.
// Not Preferred
import hpp from 'hpp'
app.use(hpp())
This import statement is very costly, as it imports a large package.
Solving this problem by creating a custom middleware:
// Preferred
const hppMiddleware = (req, res, next) => {
if (req.query && typeof req.query === "object") {
for (const key in req.query) {
if (Array.isArray(req.query[key])) {
req.query[key] = req.query[key][req.query[key].length - 1];
}
}
}
next();
};
app.use(hppMiddleware);
Logging is crucial for understanding your application's behavior and diagnosing issues. Use Morgan for logging HTTP requests in the console, and Winston for more versatile logging, including file storage:
Morgan: It can be used for logging HTTP requests in the console.
app.use(morgan('dev'))
Winston: It can be used for logging all types of requests in a separate file or in the console or in both.
import { createLogger, transports, format } from "winston";
const logger = createLogger({
level: "verbose",
format: format.combine(format.timestamp(), format.json()),
transports: [
// new transports.Console({
// format: format.combine(
// format.colorize(),
// format.simple()
// ),
// }),
new transports.File({ filename: "logs/error.log", level: "error" }),
new transports.File({ filename: "logs/combined.log" }),
],
});
For using logger in each request
logger.info("Request received: ${req.method} ${req.url}")
For using logger as middleware
const loggerMiddleware = (req, res, next) => {
logger.info(
`${req.method} ${req.protocol}: ${req.get("host")}${req.originalUrl}`
);
next();
};
app.use(loggerMiddleware);
We ignore them sometimes
Perform Input Validation
Only Return What Is Necessary
Remove Unnecessary Routes
Implement Captcha
Nodejs Security - OWASP Cheat Sheet Series
Node.js Security Best Practices | Node.js
Top 10 Node.js Security Best Practices - Risks & Prevention | Snyk
By incorporating these backend security best practices, you fortify your Node.js application against common vulnerabilities. Regularly update dependencies, control resource access, set HTTP headers, and employ logging to maintain a robust and secure backend. Happy Coding🎊!!