BRUCE_FEBRUCE_FE

EN/CH Mode

BRUCE_FE Interview Notes - CSRF Cookie Cross-Site Attack

In-depth analysis of CSRF attack principles, hazards, and defense mechanisms. Learn how to use SameSite Cookie, CSRF Token, and other methods to protect web applications from cross-site request forgery attacks.

影片縮圖

Lazy to read articles? Then watch videos!

What is CSRF Attack?

Cross-Site Request Forgery (CSRF) is an attack that tricks you into performing unintended actions without your knowledge. Imagine someone forging your signature to withdraw money from the bank.

🔍 How CSRF Attack Works

1. You log in to the bank website (bank.com)

Browser receives authentication cookie

2. Visit malicious website (evil.com)

Contains code that automatically sends requests (with cookies)

3. Malicious request includes cookie

Bank website mistakenly thinks it's your operation

Simple CSRF attack example:

<!-- CSRF attack using GET method -->
<img src="https://bank.com/transfer?to=hacker&amount=1000" style="display:none">
<!-- When you visit a page containing this code, a transfer request is automatically sent -->

<!-- CSRF attack using POST method -->
<form id="csrf-form" action="https://bank.com/api/transfer" method="POST" style="display:none">
  <input type="hidden" name="to" value="hacker">
  <input type="hidden" name="amount" value="1000">
</form>
<script>
  // Automatically submit the form after page load
  document.addEventListener('DOMContentLoaded', function() {
    document.getElementById('csrf-form').submit();
  });
</script>

How CSRF Attack Works

Three key conditions for a successful CSRF attack:

  1. 1. The user is authenticated on the target site and has an authentication cookie.
  2. 2. Cookies are sent automatically with requests, even from different sites.
  3. 3. The attacker tricks the victim into visiting a malicious page or clicking a malicious link.

Attack Flow Example

Scenario Setup:

  • 1. User is logged in to the bank website (bank.com), browser stores authentication cookie.
  • 2. The bank website has a transfer API: POST /api/transfer
  • 3. The attacker owns a malicious website (evil.com)

Step 1: User logs in to the bank website

// Cookie received after user logs in to the bank website
Set-Cookie: session=abc123; Domain=bank.com; Path=/; HttpOnly; Secure

Step 2: Attacker prepares malicious website

<!-- HTML code on malicious site (evil.com) -->
<html>
  <body>
    <h1>Win a free prize!</h1>
    
    <!-- Hidden form auto-submitted -->
    <form id="csrf-form" action="https://bank.com/api/transfer" method="POST" style="display:none;">
      <input type="hidden" name="to" value="attacker-account" />
      <input type="hidden" name="amount" value="1000" />
    </form>
    
    <script>
      // Automatically submit the form after page load
      window.onload = function() {
        document.getElementById("csrf-form").submit();
      }
    </script>
  </body>
</html>

Step 3: Victim visits malicious website

When the user visits evil.com, the malicious script automatically submits the form to bank.com, and the browser automatically attaches the user's bank cookie.

POST /api/transfer HTTP/1.1
Host: bank.com
Cookie: session=abc123
Content-Type: application/x-www-form-urlencoded

to=attacker-account&amount=1000

Step 4: Bank website processes the request

The bank website sees a valid session cookie, assumes the request is from a legitimate user, and processes the transfer.

Common Forms of CSRF Attacks

1. GET Request Attack

Use image tags or other resource requests to perform attacks:

<!-- Malicious image tag triggers GET request -->
<img src="https://bank.com/api/transfer?to=attacker&amount=1000" width="0" height="0" />

2. POST Request Attack

As in the previous example, use an auto-submitted form:

<form id="csrf-form" action="https://bank.com/api/transfer" method="POST">
  <input type="hidden" name="to" value="attacker-account" />
  <input type="hidden" name="amount" value="1000" />
</form>
<script>document.getElementById("csrf-form").submit();</script>

3. AJAX Request Attack

Use JavaScript to initiate XMLHttpRequest or fetch requests:

// Note: This method is usually restricted by same-origin policy and CORS
fetch('https://bank.com/api/transfer', {
  method: 'POST',
  credentials: 'include', // Key: include cookies
  headers: {
    'Content-Type': 'application/x-www-form-urlencoded',
  },
  body: 'to=attacker-account&amount=1000'
})
.then(response => console.log('CSRF attack succeeded'))
.catch(error => console.error('CSRF attack failed', error));

4. Clickjacking (UI Redressing)

Combining transparent iframes and social engineering to trick users into clicking malicious buttons:

<style>
  .game { position: relative; width: 500px; height: 500px; }
  .overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; z-index: 10; }
  iframe { position: absolute; top: 0; left: 0; width: 500px; height: 500px; opacity: 0.0001; }
</style>

<div class="game">
  <button class="overlay">Click to claim prize</button>
  <!-- Semi-transparent iframe positioned above the bank site's 'Confirm Transfer' button -->
  <iframe src="https://bank.com/transfer?to=attacker&amount=1000"></iframe>
</div>

CSRF Attack Defense Strategies

❌ Common Misconceptions

'CORS restricts cross-site requests, so CSRF is not possible'

Wrong! Browsers allow cross-site form submissions or image requests (e.g., <img src="...">), which are not restricted by CORS.

There are several ways to protect your site from CSRF attacks. Here are the most effective strategies:

1. SameSite Cookie Attribute

This is currently the most recommended defense. By setting the SameSite attribute on cookies, you can restrict cookies from being sent with cross-site requests:

Set-Cookie: session=abc123; SameSite=Strict; Path=/; HttpOnly; Secure

SameSite options:

  • 1. Strict: Cookies are only sent for requests from the same site (most secure, but worse user experience)
  • 2. Lax: Cookies are sent for top-level navigation and GET requests to the target site, but not for other cross-site requests (balance of security and UX, default in modern browsers)
  • 3. None: Allows cookies to be sent cross-site, but must also set Secure attribute (not secure, use only when necessary)

2. CSRF Token

Use randomly generated tokens to verify the legitimacy of requests:

Server generates and stores CSRF Token:

// Node.js Express example
const crypto = require('crypto');

app.get('/form', (req, res) => {
  // Generate random token
  const csrfToken = crypto.randomBytes(16).toString('hex');
  
  // Store in user session
  req.session.csrfToken = csrfToken;
  
  // Embed token in form
  res.send(
    '<form action="/api/transfer" method="POST">' +
    '<input type="hidden" name="_csrf" value="' + csrfToken + '" />' +
    '<!-- other form fields -->' +
    '<button type="submit">Confirm Transfer</button>' +
    '</form>'
  );
});

Server validates the token:

// Middleware to validate CSRF Token
app.post('/api/transfer', (req, res) => {
  // Get token from request
  const csrfToken = req.body._csrf;
  
  // Validate token
  if (csrfToken !== req.session.csrfToken) {
    return res.status(403).json({ error: 'CSRF token validation failed' });
  }
  
  // Token valid, process request
  // ...
});

CSRF Token is effective because malicious sites cannot obtain the cross-origin token value, so they cannot construct requests with the correct token.

3. Double Submit Cookie

No server storage required, store the token in both the cookie and the request parameter:

// Set a cookie only for CSRF protection
app.get('/form', (req, res) => {
  const csrfToken = crypto.randomBytes(16).toString('hex');
  
  // Set cookie (add SameSite=Lax for better security)
  res.cookie('csrf', csrfToken, { 
    httpOnly: false, 
    sameSite: 'Lax',
    secure: true 
  });
  
  // Also include the same token in the form
  res.send(
    '<form action="/api/transfer" method="POST">' +
    '<input type="hidden" name="_csrf" value="' + csrfToken + '" />' +
    '<!-- other form fields -->' +
    '</form>'
  );
});

// On validation, compare the token in the cookie and the one submitted in the form
app.post('/api/transfer', (req, res) => {
  if (req.cookies.csrf !== req.body._csrf) {
    return res.status(403).json({ error: 'Validation failed' });
  }
  // Process request...
});

Common CSRF Interview Questions

1. What is the difference between CSRF and XSS attacks?

A: The attack methods and purposes are different:

CSRF

Uses logged-in state to send forged requests

Cannot read data, can only perform actions

Defense: Validate request origin

XSS

Injects and executes malicious scripts

Can read data and execute arbitrary JS

Defense: Filter input, encode output

2. Why is SameSite Cookie an effective defense against CSRF?

A: SameSite restricts cookies to be sent only in specific situations:

Strict

Only same-site requests send cookies

Set-Cookie: session=123; SameSite=Strict;

Lax (Modern Browser Default)

Allows top-level navigation and GET requests to send cookies

Set-Cookie: session=123; SameSite=Lax;

CSRF attacks require cookies to be sent automatically, SameSite directly blocks this mechanism.

3. How does CSRF Token work?

A: Use randomly generated tokens to verify the legitimacy of requests:

1. Generate Token

Server generates random token

2. Embed in Page

Put in form or JS request

3. Validate Token

Check if token matches

// Frontend form
<form>
  <input type="hidden" name="_csrf" value="random token">
  <!-- Other form fields -->
</form>

// Backend validation
if (req.body._csrf !== session.csrfToken) {
  return res.status(403).send("Request denied");
}

Due to same-origin policy, malicious sites cannot read the target site's token, so they cannot construct valid requests.

4. Do I still need CSRF Token when setting SameSite Cookie?

A: Usually not both defenses are needed at the same time, but in some cases, both might be needed:

SameSite=Lax (recommended setting) is usually sufficient:

  • 1. Prevents most CSRF attacks
  • 2. Allows normal navigation from external site links
  • 3. Default behavior in modern browsers

When to use CSRF Token together:

  • 1. Need to support older browsers (don't support SameSite attribute)
  • 2. Must use SameSite=None (e.g., third-party integration scenarios)
  • 3. Need higher security level applications (e.g., financial services)
  • 4. Practice of Defense in Depth strategy
// Best practice: Combine both
// 1. Set SameSite Cookie
app.use(session({
  cookie: {
    secure: true,
    httpOnly: true,
    sameSite: 'lax' // Default value, blocks most CSRF
  }
}));

// 2. Critical operations still use CSRF Token as additional protection
app.post('/api/payment', csrfProtection, (req, res) => {
  // Process payment request
});

Balance of security and compatibility: SameSite Cookie provides basic protection, while CSRF Token can provide additional security layers when needed.