Prevent Cross-Site Request Forgery
Cross-Site Request Forgery (CSRF) is an attack that forces authenticated users to execute unwanted actions on a web application. When a user is authenticated, their browser automatically includes session cookies with requests. Attackers can craft malicious pages that trigger requests to vulnerable applications, causing actions to be performed without the user's consent.
Language: Python / Django
CSRF Exempt Decorator
Incorrect (using @csrf_exempt decorator):
from django.http import HttpResponse
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def my_view(request):
return HttpResponse('Hello world')Correct (remove csrf_exempt decorator):
from django.http import HttpResponse
def my_view(request):
return HttpResponse('Hello world')References:
Language: JavaScript / Express
Missing CSRF Middleware
⚠ Deprecation Notice: The
csurfnpm package is deprecated and should not be used in new projects. Use a maintained alternative such ascsrf-csrf(Double-Submit Cookie pattern) orcsrf-sync(Synchronizer Token pattern).
Incorrect (Express app without CSRF protection):
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
app.post('/process', bodyParser.urlencoded({ extended: false }), function(req, res) {
res.send('data is being processed')
})Correct — Option A: csrf-csrf (Double-Submit Cookie pattern):
const express = require('express')
const cookieParser = require('cookie-parser')
const { doubleCsrf } = require('csrf-csrf')
const { doubleCsrfProtection, generateToken } = doubleCsrf({
getSecret: () => process.env.CSRF_SECRET,
cookieName: '__Host-psifi.x-csrf-token',
cookieOptions: { sameSite: 'strict', secure: true },
})
const app = express()
app.use(cookieParser())
app.use(doubleCsrfProtection)
// Generate a token for forms/SPA clients
app.get('/csrf-token', (req, res) => {
res.json({ token: generateToken(req, res) })
})Correct — Option B: csrf-sync (Synchronizer Token pattern):
const express = require('express')
const { csrfSync } = require('csrf-sync')
const { csrfSynchronisedProtection, generateToken } = csrfSync()
const app = express()
app.use(csrfSynchronisedProtection)Additional defenses (complement token-based CSRF protection):
- Set
SameSite=StrictorSameSite=Laxon session cookies. - Validate
Sec-Fetch-Site/Originheaders (Fetch Metadata) to reject cross-origin requests at the edge.
References:
- csrf-csrf (Double-Submit Cookie)
- csrf-sync (Synchronizer Token)
- csurf — deprecated (do not use in new projects)
- OWASP CSRF Prevention Cheat Sheet
- OWASP Fetch Metadata / Resource Isolation Policy
- MDN SameSite Cookies
Language: Java / Spring
CSRF Disabled
Incorrect (explicitly disabling CSRF protection):
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated();
}
}Correct (CSRF protection enabled by default):
@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated();
}
}References:
Language: Ruby / Rails
Missing CSRF Protection
Incorrect (controller without protect_from_forgery):
class DangerousController < ActionController::Base
puts "do more stuff"
endCorrect (controller with protect_from_forgery):
class SafeController < ActionController::Base
protect_from_forgery with: :exception
puts "do more stuff"
endReferences:
General References:
- CWE-352: Cross-Site Request Forgery (CSRF)
- OWASP Top 10 A01:2021 - Broken Access Control
- OWASP CSRF Prevention Cheat Sheet