Learn about CSRF and how to protect against it in your nodejs app

CSRF (Cross-Site Request Forgery) is a web security vulnerability that tricks a user into performing unwanted actions on a web application where they are authenticated. An attacker exploits the trust that a web application has in the user’s browser by crafting malicious requests that appear to originate from the user.

How CSRF Works

1.Victim Authentication: The user logs into a trusted website (example.com) and has an active session (e.g., a session cookie).

2.Malicious Action:

The attacker crafts a malicious link or form that sends a request to example.com. The victim unknowingly triggers the malicious request by clicking a link, visiting a page, or loading an image.

3.Exploitation:

The browser includes the user’s session cookie or authentication token with the malicious request. The server processes the request as if it were made by the user, potentially performing unauthorized actions (e.g., transferring money, changing account settings).

Use CSRF Tokens:

import csrf from "csurf";

// Allow CSRF tokens to be sent via the "CSRF-Token" header or `_csrf` cookie
const csrfProtection = csrf({
  cookie: true,
  value: (req) => req.headers["csrf-token"] || req.body._csrf, // Check both headers and body for the token
});

export default csrfProtection;
import csrfProtection from "./middleware/csrfMiddleware.js"; // Use your custom CSRF middleware
// CSRF Token Endpoint
app.get("/csrf-token", csrfProtection, (req, res) => {
  res.json({ csrfToken: req.csrfToken() });
});

example of protecting a route

import express from 'express';
const router = express.Router();
import csrfProtection from '../middleware/csrfMiddleware.js'; 

import { changePassword } from '../controllers/authController.js';

router.post('/change-password', ensureAuthenticated, csrfProtection, changePassword); 

export default router;

Require same site cookies:

// Session configuration
app.use(
  session({
    store: MongoStore.create({
      mongoUrl: process.env.MONGO_URI,
    }),
    secret: process.env.SESSION_SECRET,
    resave: false,
    saveUninitialized: false,
    cookie: {
      secure: process.env.NODE_ENV === "production", // Use HTTPS in production
      httpOnly: true, // Prevent JavaScript from accessing cookies
      sameSite: process.env.NODE_ENV === "production" ? "none" : "lax", // 'none' for cross-origin requests
      maxAge: 1000 * 60 * 60 * 24, // 1 day cookie expiration
    },
  })
);

Implement CORS policies:

const corsOptions = {
  origin: process.env.NODE_ENV === "production"
    ? ["https://www.example.com", "https://example.com"]
    : "http://localhost:3000", // Allow localhost during development
  methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
  credentials: true, // Allow sending credentials (cookies)
};

Why Exclude GET Requests?

GET requests are meant to be safe and idempotent, meaning they should not cause any state changes. Including CSRF tokens for GET requests is unnecessary and can lead to usability issues, such as making bookmarks or links unusable.

API Requests Secured via Other Methods:

If you’re using OAuth2, JWT, or similar tokens for API security, CSRF tokens might not be necessary because the API uses Authorization headers rather than cookies for authentication.

Thank you!

0
Subscribe to my newsletter

Read articles from Hooman Pegahmehr directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Hooman Pegahmehr
Hooman Pegahmehr

Hooman Pegahmehr is a performance-driven, analytical, and strategic Technology Management Professional, employing information technology best practices to manage software and web development lifecycle in alignment with client requirements. He builds high-quality, scalable, and reliable software, systems, and architecture while ensuring secure technology service delivery as well as transcending barriers between technology, creativity, and business, aligning each to capture the highest potential of organization resources and technology investments. He offers 8+ years of transferable experience in creating scalable web applications and platforms using JavaScript software stack, including MongoDB, Express, React, and Node, coupled with a focus on back-end development, data wrangling, API design, security, and testing. He utilizes a visionary perspective and innovative mindset to collect and translate technical requirements into functionalities within the application while writing codes and producing production-ready systems for thousands of users. He designs, develops, and maintains fully functioning platforms using modern web-based technologies, including MERN Stack (MongoDB, Express, React, Node). As a dynamic and process-focused IT professional, Hooman leverages cutting-edge technologies to cultivate differentiated solutions and achieve competitive advantages while supporting new systems development lifecycle. He excels in creating in-house solutions, replacing and modernizing legacy systems, and eliminating outsourcing costs. He exhibits verifiable success in building highly responsive full-stack applications and incident management systems using advanced analytical dashboards while translating complex concepts in a simplified manner. Through dedication towards promoting a culture of collaboration, Hooman empowers and motivates diverse personnel to achieve technology-focused business objectives while administering coaching, training, and development initiatives to elevate personnel performance and achieve team synergy. He earned a winning reputation for transforming, revitalizing, streamlining, and optimizing multiple programs and web-based applications to drive consistent communications across cross-functional organization-wide departments. He manages multiple projects from concept to execution, utilizing prioritization and time management capabilities to complete deliverables on time, under budget, and in alignment with requirements.