CSRF

CSRF

Cross-Site Request Forgery (CSRF) - A Developer’s Guide

What is CSRF?

Cross-Site Request Forgery (CSRF) is a web security vulnerability that tricks a user into executing unwanted actions on a trusted website where they are authenticated.

Example Attack Scenario:

  1. A user logs into bank.com and their session is authenticated.
  2. They visit a malicious site while still logged into bank.com.
  3. The malicious site submits a forged request to bank.com, triggering actions like transferring money.
  4. Since the user is already logged in, the request is processed as if the user intended it.

How CSRF Works

Example of a CSRF Attack

Let’s say a banking website allows users to transfer money via a simple GET request:

<a href="https://bank.com/transfer?amount=1000&to=attacker_account">Click Here!</a>

If a logged-in user clicks the link, their browser automatically sends their session cookies to bank.com , completing the transfer without their consent.


CSRF Protection Techniques

To prevent CSRF attacks, websites must verify that requests come from a trusted source.

1. CSRF Tokens (Best Practice)

A CSRF token is a random, unique string generated per session or request. The server validates this token before processing actions.

Implementation in Node.js (Express)

Install csurf middleware:

npm install csurf

Apply it to your Express app:

const csrf = require("csurf");
const cookieParser = require("cookie-parser");

app.use(cookieParser());
app.use(csrf({ cookie: true }));

app.get("/form", (req, res) => {
  res.send(`<form method="POST" action="/transfer">
              <input type="hidden" name="_csrf" value="${req.csrfToken()}">
              <input type="text" name="amount" placeholder="Enter Amount">
              <button type="submit">Transfer</button>
            </form>`);
});

app.post("/transfer", (req, res) => {
  // Only processes if valid _csrf token is sent
  res.send("Transfer successful");
});

Why It Works?

  • CSRF tokens are tied to the user’s session.
  • Attackers cannot guess or reuse tokens.

2. SameSite Cookies

SameSite prevents cookies from being sent with cross-origin requests.

Set SameSite=Strict in Cookies

app.use(session({
  secret: "your_secret",
  cookie: { sameSite: "Strict", httpOnly: true }
}));
  • Strict: Cookies only sent for same-site requests (Best for security).
  • Lax: Cookies sent for top-level navigations only.
  • None: Cookies sent for all requests (Requires HTTPS).

3. Verifying the Referrer / Origin

Check if requests come from an expected origin:

app.post("/transfer", (req, res) => {
  const origin = req.get("Origin");
  if (origin !== "https://bank.com") {
    return res.status(403).send("Forbidden");
  }
  res.send("Transfer successful");
});

Downside: Not all browsers send the Origin header in same-site requests.


4. Disable GET for State-Changing Actions

Avoid making sensitive actions accessible via GET requests. Use POST or PUT instead.

Bad:

<a href="https://bank.com/transfer?amount=1000&to=attacker">Transfer Money</a>

Good:

<form method="POST" action="/transfer">
  <input type="hidden" name="amount" value="1000">
  <button type="submit">Transfer</button>
</form>

CSRF vs. XSS

Attack TypeCSRFXSS (Cross-Site Scripting)
Exploits user’s authentication✅ Yes❌ No
Injects malicious script into a website❌ No✅ Yes
Requires victim to be logged in✅ Yes❌ No
Prevented by CSRF tokens✅ Yes❌ No
Prevented by input validation❌ No✅ Yes

Testing for CSRF (Manual & Automated)

Manual Testing

  • Identify state-changing requests (e.g., money transfer, password change).
  • Try executing them from an unauthorized source (e.g., another website).
  • Check if the action succeeds without authentication validation.

Automated Testing

Use tools like:

  • OWASP ZAP (Zed Attack Proxy)
  • Burp Suite
  • Postman (For testing request behavior)

Real-World CSRF Attack Example

2019: GitHub CSRF Vulnerability

  • GitHub had a CSRF issue where attackers could trick users into adding their SSH keys.
  • GitHub quickly patched it by enforcing CSRF tokens.

Conclusion

CSRF is dangerous but preventable using:

  • CSRF tokens (Best approach)
  • SameSite cookies
  • Checking Origin headers
  • Avoiding GET for state-changing requests

Always test your web applications for CSRF vulnerabilities to prevent unauthorized actions.