Skip to main content
Mohammad Shehadeh — home (MSH monogram, letter M filled with the Palestinian flag)

CSRF Attacks: How Hackers Can Hijack Your Users Accounts

Published on
3 min read

A user logs into their bank, then visits a malicious site in another tab. Without knowing it, the malicious site tricks their browser into sending money. This is CSRF—Cross-Site Request Forgery. It's a simple but dangerous attack that exploits how browsers send authentication cookies with every request.

How CSRF Attacks Work

Your browser sends cookies to websites you're logged into. An attacker exploits this with a hidden form on their site that sends a request to the bank:

malicious-form.html
1<form id="csrf" action="https://bank.com/transfer" method="POST">
2  <input type="hidden" name="account" value="attacker" />
3  <input type="hidden" name="amount" value="1000" />
4</form>
5<script>document.getElementById('csrf').submit();</script>

When you visit this page while logged into your bank, the form submits on its own. Your browser includes your bank authentication cookies, so the bank thinks it's a legitimate request from you. The attacker never needs your password.

Key Point

CSRF only works with state-changing operations (like sending money or changing settings). Browsers don't send cookies with requests from other websites, but they still send the request. The bank processes it because the cookies look real.

Essential Defenses

CSRF Tokens

Generate a unique token for each user session. Require it with every form that changes data:

protected-form.html
1<form action="/transfer" method="POST">
2  <input type="hidden" name="_csrf" value="random-unique-token" />
3  <input type="text" name="amount" />
4  <button>Transfer</button>
5</form>

Validate the token on your server:

validation.ts
1app.post('/transfer', (req, res) => {
2  if (req.body._csrf !== req.session.csrfToken) {
3      return res.status(403).json({ error: 'Invalid token' });
4  }
5  processTransfer(req.body);
6});

Why it works: The token is unique per session and never stored as a cookie. Attackers can't guess it or read it from your website.

SameSite Cookies

Control when the browser sends authentication cookies. Combine with httpOnly for full protection:

cookie-config
1// SameSite=Lax: Send for top-level navigation, not hidden sub-requests
2// httpOnly: Block JavaScript from accessing the cookie
3// Secure: Only send over HTTPS
4Set-Cookie: sessionId=abc123; SameSite=Lax; HttpOnly; Secure;

What each flag does:

  • SameSite=Lax - Prevents the browser from sending cookies in cross-site POST requests (blocks CSRF)
  • HttpOnly - Prevents JavaScript from reading the cookie (blocks XSS attacks)
  • Secure - Only send over HTTPS connections
Important

SameSite protects against CSRF, but older browsers don't support it. Some APIs also bypass SameSite by using Authorization headers instead of cookies. Always use CSRF tokens as a secondary defense.

Origin Validation

Verify that requests come from your own domain:

origin-check.ts
1app.post('/transfer', (req, res) => {
2  if (!['https://yoursite.com'].includes(req.headers.origin)) {
3      return res.status(403).send('Invalid origin');
4  }
5  processTransfer(req.body);
6});

Why You Need Both Tokens and Cookies

SameSite cookies alone aren't enough. Here's why:

bypass-example.js
1// Attacker bypasses SameSite by using Authorization header
2fetch('https://bank.com/transfer', {
3  method: 'POST',
4  headers: {
5      'Authorization': 'Bearer token-from-localstorage'
6  },
7  body: JSON.stringify({ amount: 1000 })
8});
9// SameSite=Lax doesn't block this!
10// But CSRF token validation would catch it

Defense layers:

  • SameSite cookies block automatic cookie transmission (CSRF prevention)
  • httpOnly prevents JavaScript theft (XSS prevention)
  • CSRF tokens validate that the request is legitimate (secondary CSRF defense)
  • Origin validation confirms the request source

Use all three together for complete protection.

Quick Defense Checklist

  • ✅ Use CSRF tokens on all forms that change data
  • ✅ Set SameSite=Lax on authentication cookies
  • ✅ Validate the origin of requests
  • ✅ Never use GET requests for state-changing operations
  • ✅ Use HTTPS only
  • ✅ Regenerate tokens after user login

Real Impact

CSRF has affected major websites: Twitter (2010), YouTube (2008), and banking platforms. Modern frameworks include built-in CSRF protection—use it.

Bottom Line

CSRF attacks are simple to execute but easy to prevent. Use defense in depth: CSRF tokens + SameSite cookies + origin validation. Your users depend on it.

Related Articles

GET IN TOUCH

Let's work together

I build fast, accessible, and delightful digital experiences for the web. Whether you have a project in mind or just want to connect, I'd love to hear from you.

Get in touch

or reach out directly at hello@mohammadshehadeh.com