Detailed Explanation of CSRF Attack and Defense

Detailed Explanation of CSRF Attack and Defense

I. Knowledge Point Description
CSRF (Cross-Site Request Forgery) is a malicious attack where the attacker tricks a logged-in user of a trusted website into performing unintended actions without their knowledge. Unlike XSS, which exploits the user's trust in the website, CSRF exploits the website's trust in the user's browser.

II. Detailed Attack Principle

1. Prerequisites for Attack

  • The user is logged into the target website (has a valid session cookie).
  • The user visits a malicious page constructed by the attacker.
  • The target website lacks effective CSRF protection measures.

2. Example of a Typical Attack Scenario
Assume the bank website's transfer interface is:

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

to_account=attacker_account&amount=1000

Malicious page constructed by the attacker:

<!-- Malicious page hidden on a third-party website -->
<body onload="document.forms[0].submit()">
  <form action="https://bank.com/transfer" method="POST">
    <input type="hidden" name="to_account" value="attacker_account">
    <input type="hidden" name="amount" value="1000">
  </form>
</body>

3. Attack Execution Process

  • The user logs into bank.com, and the session cookie is saved in the browser.
  • The user visits the malicious page constructed by the attacker.
  • The browser automatically submits the hidden form, carrying the user's legitimate cookie.
  • The bank server verifies the cookie as valid and executes the transfer operation.

III. Detailed Defense Measures

1. Verify Referer/Origin Headers

  • Principle: Check if the request origin is within the whitelist.
  • Implementation Method:
def check_referer(request):
    referer = request.headers.get('Referer')
    origin = request.headers.get('Origin')
    
    # Allow requests from bank.com
    if referer and 'bank.com' in referer:
        return True
    if origin and origin == 'https://bank.com':
        return True
    return False
  • Limitations: Some browsers may not send the Referer, and it can be tampered with.

2. CSRF Token Protection (Recommended Solution)

  • Principle: Embed a random token in the form, and the server verifies the token's validity.

Server-side Implementation Steps:

import secrets

class CSRFTokenMiddleware:
    def generate_token(self):
        return secrets.token_urlsafe(32)
    
    def verify_token(self, request_token, session_token):
        return secrets.compare_digest(request_token, session_token)

# Inject Token when rendering the form
def render_transfer_form(request):
    token = request.session.get('csrf_token')
    if not token:
        token = generate_token()
        request.session['csrf_token'] = token
    
    return render_template('form.html', csrf_token=token)

Client-side Form Example:

<form action="/transfer" method="POST">
    <input type="hidden" name="csrf_token" value="{{ csrf_token }}">
    <input type="text" name="to_account">
    <input type="number" name="amount">
    <button type="submit">Transfer</button>
</form>

Server-side Verification Logic:

def transfer_handler(request):
    if request.method == 'POST':
        form_token = request.POST.get('csrf_token')
        session_token = request.session.get('csrf_token')
        
        if not verify_token(form_token, session_token):
            return HttpResponse('CSRF verification failed', status=403)
        
        # Execute transfer logic
        process_transfer(request)

3. SameSite Cookie Attribute

  • Principle: Controls the scope of cookie sending to prevent cross-site requests from carrying cookies.
  • Three Modes:
    • Strict: Completely prohibits cross-site cookie carrying.
    • Lax: Allows cross-site requests with safe methods (GET).
    • None: No restrictions (requires the Secure attribute).

Setting Example:

Set-Cookie: sessionid=abc123; SameSite=Lax; Secure; HttpOnly

4. Double Cookie Verification

  • Principle: Include tokens in both request parameters and cookies; the server verifies consistency.
// Frontend automatically adds Token parameter
fetch('/api/transfer', {
    method: 'POST',
    headers: {
        'Content-Type': 'application/json',
        'X-CSRF-Token': getCookie('csrf_token')
    },
    body: JSON.stringify(data)
})

IV. Best Practices Summary

  1. Use POST Requests for Critical Operations: Avoid modifying data via GET requests.
  2. CSRF Token as Core Protection: Enforce token verification for state-changing operations.
  3. Set SameSite Attribute Reasonably: Session cookies are recommended to be set as SameSite=Lax.
  4. Secondary Verification for Sensitive Operations: Important operations require password or SMS verification.
  5. Deepen Defense: Combine multiple protection measures to form a defense-in-depth strategy.

By understanding the attack principle of CSRF and systematically studying defense solutions, you can effectively protect web applications from such threats.