Perfect! Let’s merge everything into a final, complete, and structured reference for identifying, extracting, and injecting CSRF / anti-forgery tokens in ZAP for form-based authentication, in a way that’s easy to use and reference. I’ll make it clear, framework-specific, and also include universal patterns and practical ZAP usage.
Form-Based Authentication — CSRF / Anti-Forgery Tokens in ZAP
Form-based login requires dynamic handling of CSRF or anti-forgery tokens to prevent login failures. Modern web apps often embed these tokens in hidden fields, meta tags, or cookies. ZAP can detect and inject them automatically if configured correctly.
1. General bodyTemplate Pattern
The POST request body generally looks like this:
username={identifier}&password={password}&Login=Login&<token_field>={%token_placeholder%}
{identifier}→ username/email placeholder{password}→ password placeholder<token_field>→ thenameattribute of the hidden CSRF/anti-forgery input{%token_placeholder%}→ ZAP variable that dynamically injects the token
2. CSRF Token Field Names by Framework
| Framework / App | Hidden Field / Meta / Cookie | ZAP Placeholder Example | Sample Sites |
|---|---|---|---|
| Ruby on Rails | <input type="hidden" name="authenticity_token"> <meta name="csrf-token"> | {%authenticity_token%} | github.com, gitlab.com, basecamp.com, shopify.com (admin) |
| Django | <input type="hidden" name="csrfmiddlewaretoken"> Cookie csrftoken | {%csrfmiddlewaretoken%} | disqus.com, instagram.com (older), eventbrite.com |
| ASP.NET / MVC | <input type="hidden" name="__RequestVerificationToken"> Cookie .AspNetCore.Antiforgery.* | {%__RequestVerificationToken%} | microsoft.com portals, stackoverflow.com (partial), enterprise apps |
| Laravel / Symfony / CodeIgniter | <input type="hidden" name="_token"> / <input name="csrf_token"> / <input name="CSRFToken"> / <input name="csrf_test_name"> Cookie XSRF-TOKEN | {%_token%}, {%csrf_token%}, {%CSRFToken%}, {%csrf_test_name%} | laracasts.com, symfony.com |
| Spring MVC (Java) | <input type="hidden" name="_csrf"> <meta name="_csrf"> Cookie XSRF-TOKEN | {%_csrf%} | spring.io, enterprise Java apps |
| PHP (DVWA / Generic) | <input type="hidden" name="user_token"> / token / csrf / _token / nonce | {%user_token%} / {%token%} | DVWA, generic PHP apps |
| WordPress | <input name="_wpnonce"> / <input name="wp_nonce"> | {%_wpnonce%} | self-hosted WordPress |
3. Universal Patterns to Look For
Hidden Input Names to Grep:
authenticity_token → Rails
csrfmiddlewaretoken → Django
__RequestVerificationToken → ASP.NET
_token → Laravel
csrf_token → Symfony / generic
_csrf → Spring
user_token → DVWA / generic PHP
CSRFToken → CodeIgniter
_wpnonce → WordPress
token → generic fallback
nonce → generic fallback
Meta Tags to Grep:
<meta name="csrf-token" → Rails
<meta name="_csrf" → Spring
Cookie Names to Grep:
csrftoken → Django
XSRF-TOKEN → Laravel / Angular default
.AspNetCore.Antiforgery → ASP.NET Core
4. How to Identify Unknown Frameworks
- View page source → Ctrl+U or browser “View Source”.
- Search for
type="hidden"in the<form>element. - Look at the
nameattribute of hidden inputs near the username/password fields. - Cross-check with the table above.
Alternative using DevTools:
- Open browser DevTools → Network tab
- Submit the login form manually
- Check the POST request payload: any extra hidden field besides username/password is likely a CSRF token
- Check the login page cookies: look for csrftoken, XSRF-TOKEN, .AspNetCore.*
5. Form-Based Login BodyTemplate Examples
| Framework / App | Required Fields (Generic) | Example bodyTemplate | CSRF / Anti-Forgery Token Placeholder |
|---|---|---|---|
| DVWA / Generic PHP | username, password, optional Login button | username={identifier}&password={password}&Login=Login&user_token={%user_token%} | user_token |
| Rails / GitHub | login, password | login={identifier}&password={password}&authenticity_token={%authenticity_token%} | authenticity_token |
| Django (Python) | username, password | username={identifier}&password={password}&csrfmiddlewaretoken={%csrfmiddlewaretoken%} | csrfmiddlewaretoken |
| ASP.NET / MVC | username, password, optional remember_me | username={identifier}&password={password}&__RequestVerificationToken={%__RequestVerificationToken%}&remember_me={%remember_me%} | __RequestVerificationToken |
| Laravel / Symfony | email, password, optional tenant | email={identifier}&password={password}&_token={%_token%}&tenant={%tenant%} | _token |
| Spring MVC (Java) | username, password | username={identifier}&password={password}&_csrf={%_csrf%} | _csrf |
| WordPress | log, pwd | log={identifier}&pwd={password}&_wpnonce={%_wpnonce%} | _wpnonce |
| Generic / Unknown | username/email, password, plus any hidden CSRF fields | username={identifier}&password={password}&<any_extra_field>={%<any_placeholder>%}&<csrf_field>={%csrf_token%} | any hidden input detected dynamically |
Notes:
-
Dynamic placeholders:
{identifier}→ your username/email{password}→ your password{%<token_name>%}→ dynamically extracted CSRF / anti-forgery token{%<extra_field>%}→ optional dynamic fields required by app
-
CSRF / anti-forgery tokens are automatically detected by ZAP if added under Options → Anti CSRF Tokens. Examples:
user_token, authenticity_token, csrfmiddlewaretoken, __RequestVerificationToken, _token, _wpnonce, _csrf
-
Generic approach: If the app has extra fields like
remember_me,tenant, ordomain, include them with{%<field_name>%}placeholders in thebodyTemplate. -
DVWA / simple PHP apps: Often only require
username,password, anduser_token. -
Complex / modern apps: May have multiple hidden tokens, redirect fields, or dynamic per-session values. Use the placeholder pattern for all of them.
5.2 Anti-CSRF Token Config in ZAP
- Go to Options → Anti CSRF Tokens
- Add the field name(s) ZAP should automatically detect, e.g.:
authenticity_token, csrfmiddlewaretoken, __RequestVerificationToken, _token, user_token, _wpnonce - ZAP will auto-extract and inject these during scans.
The
stats.pscan.Anti CSRF Token Detectioncounter increments whenever ZAP spots a CSRF token, showing it’s actively handling them.
6. Example Full Form-Based Login (DVWA)
automation: true
scope:
entryUrls:
- "http://20.80.162.88:4280/"
includePaths:
- "http://20.80.162.88:4280.*"
excludePaths:
- "http://20.80.162.88:4280/logout.php"
- "http://20.80.162.88:4280/login.php"
- "http://20.80.162.88:4280/setup.php"
- "http://20.80.162.88:4280/security.php"
- "http://20.80.162.88:4280/vulnerabilities/csrf.*"
headers:
Cookie: "PHPSESSID={%cookie:PHPSESSID%}; security=low;"
authentication:
type: "form"
loginPageUrl: "http://20.80.162.88:4280/login.php"
loginBackendUrl: "http://20.80.162.88:4280/login.php"
bodyTemplate: "username={identifier}&password={password}&Login=Login&user_token={%user_token%}"
pollUrl: "http://20.80.162.88:4280/index.php"
loggedInRegex: "Welcome to Damn Vulnerable Web Application!"
✅ Key Takeaways
- Always reference the token field dynamically:
{%<token_field_name>%} - ZAP handles extraction from hidden fields, meta tags, and cookies
- Correct token injection ensures reliable login for DVWA, SPAs, Rails, Django, Laravel, .NET, and WordPress apps
- Use pollUrl to verify login when login response alone isn’t sufficient
Got it! Here's a polished extra section on CSRF/anti-forgery token limitations for your ZAP documentation, integrating your Claude data and keeping it consistent with the style of your previous JSON/Form-based guides.
CSRF / Anti-Forgery Token Handling — Limitations in ZAP
ZAP is powerful for automating CSRF token detection and replay, but there are some limitations you should be aware of when using automation YAML for form-based authentication.
1. What ZAP Handles Automatically
ZAP natively detects and manages hidden form field tokens, such as:
- Rails:
authenticity_token - Django:
csrfmiddlewaretoken - ASP.NET / MVC:
__RequestVerificationToken - Spring:
_csrf - Laravel / Symfony:
_token - DVWA / generic PHP:
user_token
Features:
- ✅ Automatically extracts tokens from hidden fields in login forms.
- ✅ Replays tokens in subsequent requests during crawling and scanning.
- ✅ Counts detections in
stats.pscan.Anti CSRF Token Detection. - ✅ Requires zero configuration in the automation YAML.
Example:
bodyTemplate: "username={identifier}&password={password}&user_token={%user_token%}"
ZAP replaces {%user_token%} dynamically at runtime.
2. What Requires Extra Work (Not Supported in Automation YAML)
Certain CSRF or anti-forgery token patterns cannot be expressed directly in YAML. These require inline httpsender Graal.js scripts:
| CSRF Pattern | Description | Status / Notes |
|---|---|---|
| Double submit cookie | Cookie contains token (csrftoken=abc123), but header (X-CSRFToken) must match it | ❌ Script only — cannot be done in YAML alone |
| Token in JSON script blob | Token embedded in HTML <script type="application/json">{"csrf_token":"abc123"}</script> | ❌ Script only — extract from HTML, inject in request |
| Response JSON → request header | Login response returns token ({"csrf_token":"abc123"}), next request requires it in header | ❌ Script only — intercept response, store, inject |
Notes:
- Inline scripting is possible but adds complexity.
- These advanced patterns are outside standard automation YAML scope.
- Focus on hidden form fields first; other patterns can be implemented later with scripts.
3. Summary Table
┌──────────────────────────────┬───────────────┬──────────────────────┐
│ CSRF Pattern │ ZAP Auto │ Status │
├──────────────────────────────┼───────────────┼──────────────────────┤
│ Hidden form field │ ✅ Native │ Fully supported │
│ (Rails, Django, .NET, Spring)│ │ │
├──────────────────────────────┼───────────────┼──────────────────────┤
│ Double submit cookie │ ❌ Script only│ Set aside │
│ (Angular, Instagram) │ │ │
├──────────────────────────────┼───────────────┼──────────────────────┤
│ JSON script blob in HTML │ ❌ Script only│ Set aside │
│ (Meta / Instagram apps) │ │ │
├──────────────────────────────┼───────────────┼──────────────────────┤
│ Response body → header │ ❌ Script only│ Set aside │
│ (custom APIs) │ │ │
└──────────────────────────────┴───────────────┴──────────────────────┘
⚠️ Recommendation: Start with hidden field token handling in YAML, then extend with inline scripts for double-submit, JSON, or response-to-header tokens as needed.