The one-line difference: CSRF tricks a user’s browser into sending a request the user didn’t intend; SSRF tricks your server into sending a request the attacker chose.

They both have “request forgery” in the name, so people lump them together. But they’re completely different beasts that’ll bite you in completely different ways, and the defense for one does nothing for the other. I’ve spent way too many nights debugging both, so here’s the side-by-side first, then the detail.

CSRF vs SSRF side by side

CSRF (Cross-Site Request Forgery)SSRF (Server-Side Request Forgery)
Who sends the forged requestThe victim’s browserYour application server
Whose trust is abusedThe site’s trust in the user’s cookiesThe network’s trust in the server
What the attacker needsA logged-in victim to visit their pageAny input the server turns into a URL fetch
Typical targetA state-changing endpoint (POST /transfer, /email/change)Internal hosts, cloud metadata (169.254.169.254), localhost admin ports
Attacker sees the response?No, the browser’s same-origin policy hides itSometimes (full-read SSRF); often blind
Worst caseActions taken as the victim: account takeover, transfersCloud credential theft, internal network access, sometimes RCE
Primary defensesCSRF tokens, SameSite cookies, Origin checksDestination allowlist, resolved-IP checks, egress filtering, IMDSv2
CWECWE-352CWE-918
OWASP Top 10Under A01 Broken Access ControlA10:2021; merged into A01 in the 2025 list

CSRF vs SSRF comparison infographic explaining the differences between Cross-Site Request Forgery and Server-Side Request Forgery attacks by Carl Sampson

Go deeper: the CSRF guide covers SameSite and token bypasses; the SSRF guide covers filter bypasses and cloud metadata attacks.

What is CSRF (Cross-Site Request Forgery)?

CSRF attacks exploit the trust that a website has in a user’s browser. When a user is authenticated to a website, their browser automatically includes session cookies with every request. Attackers exploit this by tricking users into making unintended requests to the target site.

How CSRF Attacks Work

  1. User logs into a legitimate website (bank.com)
  2. Browser stores authentication cookies
  3. User visits a malicious website while still logged in
  4. Malicious site triggers a request to bank.com
  5. Browser automatically includes authentication cookies
  6. Bank processes the request as if user intended it

Real CSRF Attack Example

Vulnerable Transfer Endpoint:

// Vulnerable Node.js endpoint
app.post('/transfer', (req, res) => {
    // No CSRF protection!
    const { amount, toAccount } = req.body;
    const userId = req.session.userId; // From session cookie
    
    transferMoney(userId, toAccount, amount);
    res.json({success: true});
});

Malicious Website Code:

<!-- Attacker's website -->
<form id="attack" action="https://bank.com/transfer" method="POST">
    <input type="hidden" name="amount" value="10000">
    <input type="hidden" name="toAccount" value="attacker-account">
</form>
<script>
    document.getElementById('attack').submit(); // Auto-submit
</script>

When the victim visits the malicious site while logged into the bank, $10,000 gets transferred automatically!

What is SSRF (Server-Side Request Forgery)?

SSRF attacks exploit the trust that external services have in your application server. Attackers manipulate your server into making requests to unintended destinations, often accessing internal resources that should be protected.

How SSRF Attacks Work

  1. Application accepts user-provided URL
  2. Server makes request to that URL
  3. Attacker provides internal/malicious URL
  4. Server requests internal resources
  5. Attacker gains access to sensitive data

Real SSRF Attack Example

Vulnerable Image Resize Endpoint:

# Vulnerable Python Flask endpoint
@app.route('/resize-image', methods=['POST'])
def resize_image():
    image_url = request.form.get('url')
    
    # No validation - DANGEROUS!
    response = requests.get(image_url)
    
    # Process image...
    return process_image(response.content)

SSRF Attack Payloads:

# Access AWS metadata (steal credentials)
POST /resize-image
url=http://169.254.169.254/latest/meta-data/iam/security-credentials/

# Access internal admin panel
POST /resize-image  
url=http://192.168.1.100:8080/admin

# Read local files
POST /resize-image
url=file:///etc/passwd

Key Differences: Impact and Scope

CSRF Impact

  • Account takeover - Change passwords, email addresses
  • Unauthorized transactions - Money transfers, purchases
  • Data modification - Update profiles, post content
  • Privilege escalation - Add admin users

SSRF Impact

  • Internal network access - Discover and access internal services
  • Cloud metadata theft - Steal AWS/GCP/Azure credentials
  • File system access - Read sensitive configuration files
  • Port scanning - Map internal network infrastructure

Prevention Strategies

CSRF Prevention

1. CSRF Tokens (Primary Defense)

// Express.js with csurf middleware
const csrf = require('csurf');
const csrfProtection = csrf({ cookie: true });

app.use(csrfProtection);

app.get('/transfer', (req, res) => {
    res.render('transfer', { csrfToken: req.csrfToken() });
});

app.post('/transfer', (req, res) => {
    // Token automatically validated by middleware
    transferMoney(req.session.userId, req.body.toAccount, req.body.amount);
});
<!-- HTML form with CSRF token -->
<form action="/transfer" method="POST">
    <input type="hidden" name="_csrf" value="{{csrfToken}}">
    <input type="number" name="amount" required>
    <input type="text" name="toAccount" required>
    <button type="submit">Transfer</button>
</form>
app.use(session({
    secret: 'your-secret',
    cookie: { 
        sameSite: 'strict', // or 'lax'
        secure: true,       // HTTPS only
        httpOnly: true      // Prevent XSS
    }
}));

3. Origin/Referer Header Validation

function validateOrigin(req, res, next) {
    const origin = req.get('Origin') || req.get('Referer');
    const allowedOrigins = ['https://yourdomain.com'];
    
    if (!allowedOrigins.some(allowed => origin && origin.startsWith(allowed))) {
        return res.status(403).json({error: 'Invalid origin'});
    }
    next();
}

SSRF Prevention

1. Input Validation and Allowlisting

# Python example with comprehensive validation
import re
from urllib.parse import urlparse
from ipaddress import ip_address, AddressValueError

def is_safe_url(url):
    try:
        parsed = urlparse(url)
        
        # Only allow HTTP/HTTPS
        if parsed.scheme not in ['http', 'https']:
            return False
            
        # Block private IP ranges
        try:
            ip = ip_address(parsed.hostname)
            if ip.is_private or ip.is_loopback:
                return False
        except (AddressValueError, TypeError):
            pass
            
        # Allowlist domains only
        allowed_domains = ['cdn.trusted.com', 'api.partner.com']
        if parsed.hostname not in allowed_domains:
            return False
            
        return True
    except:
        return False

@app.route('/fetch-image', methods=['POST'])
def fetch_image():
    url = request.form.get('url')
    
    if not is_safe_url(url):
        return jsonify({'error': 'Invalid URL'}), 400
        
    response = requests.get(url, timeout=5)
    return process_image(response.content)

2. Network Segmentation

# Firewall rules to block SSRF
iptables -A OUTPUT -d 169.254.169.254 -j DROP    # AWS metadata
iptables -A OUTPUT -d 10.0.0.0/8 -j DROP         # Private networks
iptables -A OUTPUT -d 172.16.0.0/12 -j DROP
iptables -A OUTPUT -d 192.168.0.0/16 -j DROP
iptables -A OUTPUT -d 127.0.0.0/8 -j DROP        # Localhost

๐ŸŽฏ Practice the SSRF half: The SSRF Target Simulator covers the server-side case hands-on โ€” reach a simulated metadata endpoint past a filter you control. No real requests are made.

Testing for Both Vulnerabilities

CSRF Testing

# Test with curl (should fail without token)
curl -X POST https://target.com/transfer \
  -d "amount=1000&toAccount=attacker" \
  -b "session=valid_session_cookie"

# Test SameSite protection  
curl -X POST https://target.com/transfer \
  -H "Origin: https://evil.com" \
  -d "amount=1000&toAccount=attacker"

SSRF Testing

# Test internal network access
curl -X POST https://target.com/fetch-image \
  -d "url=http://127.0.0.1:22"

# Test metadata access
curl -X POST https://target.com/fetch-image \
  -d "url=http://169.254.169.254/latest/meta-data/"

# Test file access
curl -X POST https://target.com/fetch-image \
  -d "url=file:///etc/passwd"

Framework-Specific Protection

Django (Python)

# CSRF protection (built-in)
MIDDLEWARE = [
    'django.middleware.csrf.CsrfViewMiddleware',
]

# Template
{% csrf_token %}

# SSRF protection
from django.core.validators import URLValidator
from django.core.exceptions import ValidationError

def safe_fetch(url):
    validator = URLValidator()
    try:
        validator(url)
        # Add additional SSRF checks
        return requests.get(url)
    except ValidationError:
        raise ValueError("Invalid URL")

Spring Boot (Java)

// CSRF protection
@EnableWebSecurity
public class SecurityConfig {
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http.csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
        return http.build();
    }
}

// SSRF protection
@Service
public class SafeHttpService {
    private static final Set<String> ALLOWED_HOSTS = Set.of("api.trusted.com");
    
    public String safeFetch(String url) {
        try {
            URL parsedUrl = new URL(url);
            if (!ALLOWED_HOSTS.contains(parsedUrl.getHost())) {
                throw new IllegalArgumentException("Host not allowed");
            }
            return restTemplate.getForObject(url, String.class);
        } catch (MalformedURLException e) {
            throw new IllegalArgumentException("Invalid URL");
        }
    }
}

Advanced Attack Scenarios

CSRF: JSON API Attacks

Modern SPAs using JSON APIs are also vulnerable:

<!-- Attacker site -->
<script>
fetch('https://api.target.com/user/update', {
    method: 'POST',
    credentials: 'include', // Include cookies
    headers: {'Content-Type': 'application/json'},
    body: JSON.stringify({email: 'attacker@evil.com'})
});
</script>

Defense: Custom request headers + CORS preflight:

// Require custom header
app.use((req, res, next) => {
    if (req.method === 'POST' && !req.get('X-Requested-With')) {
        return res.status(403).json({error: 'Missing custom header'});
    }
    next();
});

SSRF: DNS Rebinding Attacks

Attackers can bypass IP filtering using DNS:

  1. Create domain pointing to public IP
  2. After validation, change DNS to private IP
  3. Server resolves to internal network

Defense: Re-resolve DNS before making request:

def safe_request(url):
    # Validate initially
    if not is_safe_url(url):
        return None
        
    # Re-resolve before request
    time.sleep(1)  # Allow DNS changes
    if not is_safe_url(url):
        return None
        
    return requests.get(url)

Security Checklist

CSRF Prevention Checklist

  • CSRF tokens implemented for state-changing requests
  • SameSite cookies configured (Strict/Lax)
  • Origin/Referer header validation
  • Custom headers for API requests
  • Proper CORS configuration

SSRF Prevention Checklist

  • URL allowlisting implemented
  • Private IP ranges blocked
  • Network segmentation in place
  • Metadata services blocked (169.254.169.254)
  • Request timeouts configured
  • Response size limits enforced

Conclusion

CSRF and SSRF represent fundamentally different attack vectors that require distinct defense strategies:

  • CSRF targets user trust through browser sessions - defend with tokens and cookie policies
  • SSRF targets server trust through request manipulation - defend with validation and network controls

Understanding both vulnerabilities is essential for building secure web applications. Implement proper defenses during development rather than trying to retrofit security later.

Remember: security is a process, not a destination. Regularly test your applications, stay updated on new attack techniques, and maintain robust logging to detect potential attacks.

๐Ÿ“˜ SSRF Deep Dive Series:

  1. 7 Critical SSRF Attack Techniques - Master SSRF attack methods
  2. SSRF Prevention Guide - Complete defense strategies
  3. CVE-2026-27696 Analysis - Real-world SSRF bypass
  4. CSRF vs SSRF Guide - Compare both vulnerabilities (you are here)

๐ŸŽฏ Web Security Fundamentals

๐Ÿ› ๏ธ Hands-On Practice

๐Ÿ“š Python Developers