CSRF Prevention in React.js: A Practical Guide
Why CSRF Still Breaks React Apps
Cross-Site Request Forgery (CSRF) tricks a logged-in user’s browser into sending unwanted requests. In React.js, the fix is simple: use anti-CSRF tokens + SameSite cookies + “credentialed” requests. This post shows working patterns you can paste in today. React protects the UI, not your cookies. If your session cookie is sent automatically, a malicious site can trigger state-changing requests on your behalf. Let’s fix that—with code.
Core Defenses (Quick Wins)
-
Use SameSite cookies + Secure + HttpOnly.
-
Require an anti-CSRF token on every state-changing request.
-
Enforce CORS and origin/referrer checks server-side.
For more articles, see the Pentest Testing Corp blog: https://www.pentesttesting.com/blog/
1) Server: issue a CSRF token (Express + csurf
)
// server.js
import express from "express";
import cookieParser from "cookie-parser";
import csrf from "csurf";
const app = express();
app.use(cookieParser());
app.use(express.json());
// store token in cookie; validate header "X-CSRF-Token"
app.use(csrf({ cookie: { httpOnly: true, sameSite: "lax", secure: true } }));
app.get("/csrf-token", (req, res) => {
res.json({ csrfToken: req.csrfToken() });
});
app.post("/api/transfer", (req, res) => {
// your protected action
res.json({ ok: true });
});
app.listen(3000);
2) React: bootstrap axios with the token
// api.js
import axios from "axios";
axios.defaults.withCredentials = true;
export async function initCsrf() {
const { data } = await axios.get("/csrf-token");
axios.defaults.headers.common["X-CSRF-Token"] = data.csrfToken;
}
// App.jsx
import { useEffect } from "react";
import { initCsrf } from "./api";
import axios from "axios";
export default function App() {
useEffect(() => { initCsrf(); }, []);
const transfer = async () => {
await axios.post("/api/transfer", { amount: 100 });
alert("done");
};
return <button onClick={transfer}>Send $100</button>;
}
🖼 Screenshot of our free Website Vulnerability Scanner homepage
3) Using native fetch
(no axios)
// send with credentials and header
async function securePost(url, body, token) {
return fetch(url, {
method: "POST",
credentials: "include",
headers: {
"Content-Type": "application/json",
"X-CSRF-Token": token
},
body: JSON.stringify(body)
});
}
4) Set session cookie flags
// when you create the session cookie
res.cookie("sid", sid, {
httpOnly: true,
secure: true, // on HTTPS
sameSite: "lax" // or "strict" if UX allows
});
5) Alternative: double-submit cookie pattern
// server: mint token and also return it (separate from session)
import { randomBytes } from "crypto";
app.get("/csrf-alt", (req, res) => {
const t = randomBytes(24).toString("hex");
res.cookie("csrf_t", t, { secure: true, sameSite: "lax" }); // readable by JS
res.json({ t });
});
// client: read token from response and echo in header with credentials
const { t } = await (await fetch("/csrf-alt", { credentials: "include" })).json();
await fetch("/api/transfer", {
method: "POST",
credentials: "include",
headers: { "X-CSRF-Token": t, "Content-Type": "application/json" },
body: JSON.stringify({ amount: 100 })
});
🖼 Sample Assessment Report by our tool to check Website Vulnerability
![]() |
Sample vulnerability assessment report generated with our free tool, providing insights into possible vulnerabilities. |
Best practices checklist
-
Always send requests with
credentials: "include"
/axios.defaults.withCredentials = true
. -
Validate a fresh token per session; rotate on login.
-
Prefer
SameSite=Lax
orStrict
on cookies; alwaysSecure
+HttpOnly
for session. -
Block risky methods without tokens (POST/PUT/PATCH/DELETE).
-
Log and alert on CSRF validation failures.
Need hands-on help?
-
Managed IT Services: https://www.pentesttesting.com/managed-it-services/
-
AI Application Cybersecurity: https://www.pentesttesting.com/ai-application-cybersecurity/
-
Offer Cybersecurity Service to Your Client: https://www.pentesttesting.com/offer-cybersecurity-service-to-your-client/
Subscribe on LinkedIn https://www.linkedin.com/build-relation/newsletter-follow?entityUrn=7327563980778995713
Try our free Website Security Checker: https://free.pentesttesting.com/
Comments
Post a Comment