Got it! Following the exact same pattern, here’s the Form-Based Authentication — ZAP Reference Guide:
Form-Based Authentication — ZAP Reference Guide
Form-based authentication in ZAP is used for applications where login occurs via an HTML form (traditional MPAs or simple HTML apps). ZAP interacts with the login page, submits credentials, and validates authentication via cookies, tokens, or poll URL responses. This is common for DVWA, WordPress, Rails apps, Django apps, and other HTML-based web applications.
Unlike JSON-based authentication, form-based login may require handling CSRF tokens or hidden fields in the HTML form.
1. YAML Configuration Overview
automation: true # Must always be true
scope:
entryUrls:
# ⚠️ The first entry URL is critical: it will be used in the scan report.
# For form-based auth, always set this to the frontend login page / SPA URL.
- "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:
# Include session cookies and any other required 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"
# Body template with username, password, and dynamic CSRF token
bodyTemplate: "username={identifier}&password={password}&Login=Login&user_token={%user_token%}"
# Optional poll URL to verify session
pollUrl: "http://20.80.162.88:4280/index.php"
# Regex or keyword that confirms successful login
loggedInRegex: "Welcome to Damn Vulnerable Web Application!"
Additional Notes:
- Entry URL order matters: ZAP treats the first URL as the primary host in the scan context and uses it in the report.
- Form-based login: First entry URL must point to the login page (frontend).
- Poll URL verification: Recommended for apps that return 302 redirects or empty login responses.
- Include/Exclude paths: Can contain multiple domains or patterns. They are used for crawling/spidering and do not affect which URL appears in the report.
2. Key Notes
loginBackendUrl: URL where the form submits credentials. Often same asloginPageUrl.bodyTemplate: Must include username, password, and any dynamic CSRF tokens.pollUrl: Optional; used to verify login success when login response is empty or redirected.loggedInRegex: Regex/keyword used to confirm authentication after login or poll URL.
3. Verification Methods
| Method | When to Use | Notes |
|---|---|---|
| Autodetect | Simple apps like DVWA | ✅ ZAP detects login success from response; works for small, predictable forms. |
| Poll URL | Complex apps / 302 redirects / multi-step | ✅ Recommended; ensures session is valid for subsequent requests. |
Recommendation: Use poll URL verification for production apps. Autodetect is fine for lab apps.
4. Key Fields
| Field | Meaning |
|---|---|
automation | Must be true. |
scope.entryUrls | Starting URL for crawling; must point to login page. |
scope.includePaths | Regex patterns for URLs to include in scan. |
scope.excludePaths | Regex patterns for URLs to exclude (logout, static assets). |
headers | Session cookies or business headers. |
authentication.type | Must be form for form-based login. |
loginPageUrl | Login page URL. |
loginBackendUrl | Form submission URL. |
bodyTemplate | POST body template with username, password, and CSRF tokens. |
pollUrl | Optional endpoint to verify login. |
loggedInRegex | Regex/keyword to confirm successful authentication. |
5. Form-Based Authentication Scenarios
| Scenario | Setup | Notes |
|---|---|---|
| Simple apps (DVWA) | Autodetect | Works for small lab apps; ZAP detects login success automatically. |
| Apps with dynamic CSRF tokens | Poll URL + bodyTemplate | Recommended; must include CSRF token in bodyTemplate and add field name in ZAP. |
| Apps with 302 redirects or multi-step | Poll URL verification | Login response may be empty; poll URL ensures session is valid. |
6. Special Considerations
-
Dynamic CSRF Token Extraction
-
Common field names:
Framework Hidden Field Name Meta / Header / Cookie Name Rails authenticity_token csrf-token / X-CSRF-Token Django csrfmiddlewaretoken csrftoken / X-CSRFToken ASP.NET __RequestVerificationToken .AspNetCore.* / RequestVerificationToken Laravel _token / csrf_token XSRF-TOKEN / X-XSRF-TOKEN Spring _csrf X-CSRF-TOKEN / XSRF-TOKEN WordPress _wpnonce n/a DVWA/PHP user_token / token / csrf n/a -
Use
{%user_token%}inbodyTemplateto inject dynamically. -
Add field names under Options → Anti CSRF Tokens → Add Field Name in ZAP.
-
-
Poll URL Verification
- Use if login page returns redirect or empty body.
loggedInRegexshould match text on the landing page after login.
-
Headers
- Include any business headers or cookies required for authenticated session.
7. Example Configurations
7.1 Poll URL Verification (Recommended)
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"
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!"
7.2 Autodetect Verification (Simple Apps)
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"
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%}"
8. Form-Based Authentication Flow Diagram
┌───────────────────────────────┐
│ Login Page (Form) │
│ http://20.80.162.88:4280/login.php │
└───────────────┬───────────────┘
│
┌─────────────┴─────────────┐
│ │
┌────────▼─────────┐ ┌───────▼────────┐
│ Autodetect │ │ Poll URL Verification │
│ (optional) │ │ (recommended) │
└────────┬─────────┘ └────────┬─────────┘
│ │
┌────────▼─────────┐ ┌───────▼─────────┐
│ Extract CSRF / │ │ Extract CSRF / │
│ Hidden Tokens │ │ Hidden Tokens │
└────────┬─────────┘ └────────┬─────────┘
│ │
┌────────▼─────────┐ ┌───────▼─────────┐
│ Submit Login Form │ │ Submit Login Form│
│ (bodyTemplate) │ │ (bodyTemplate) │
└────────┬─────────┘ └────────┬─────────┘
│ │
┌────────▼─────────┐ ┌───────▼─────────┐
│ Session Detection │ │ Session Detection│
│ Cookies / Headers │ │ Cookies / Headers│
│ / Tokens │ │ / Tokens │
└────────┬─────────┘ └────────┬─────────┘
│ │
┌─────▼─────┐ ┌───▼─────┐
│ Headers │ │ Headers │
│ Injection │ │ Injection │
│ (Optional │ │ (Optional│
│ business │ │ business │
│ headers) │ │ headers) │
└───────────┘ └──────────┘
Notes:
- Autodetect is optional, works for simple lab apps.
- Poll URL verification is recommended for production apps.
- Always inject dynamic CSRF tokens for successful login.
- All required headers and cookies must be included for authenticated requests.
Got it! Let’s explain dynamic CSRF / anti-forgery token injection for form-based login properly, in the same style as the JSON guide, so it’s crystal clear.
Dynamic CSRF / Anti-Forgery Token Injection in Form-Based Authentication
Many modern web applications include hidden tokens in login forms to prevent CSRF attacks. ZAP needs to extract these tokens dynamically from the login page and inject them in the POST request body.
The general pattern in bodyTemplate is:
username={identifier}&password={password}&Login=Login&<token_field>={%token_placeholder%}
Where:
{identifier}→ your username or email placeholder.{password}→ your password placeholder.<token_field>→ name of the hidden input field in the login form.{%token_placeholder%}→ ZAP variable that dynamically injects the token extracted from the page.
Example Patterns by Framework
| Framework / App | Body Template Example |
|---|---|
| DVWA / Generic PHP | username={identifier}&password={password}&Login=Login&user_token={%user_token%} |
| Rails / GitHub | login={identifier}&password={password}&authenticity_token={%authenticity_token%} |
| Django | username={identifier}&password={password}&csrfmiddlewaretoken={%csrfmiddlewaretoken%} |
| ASP.NET / MVC | username={identifier}&password={password}&__RequestVerificationToken={%__RequestVerificationToken%} |
| Laravel / Symfony | email={identifier}&password={password}&_token={%_token%} |
| WordPress | log={identifier}&pwd={password}&_wpnonce={%_wpnonce%} |
How ZAP Extracts Tokens
-
From Hidden Form Fields
ZAP will scan the login page HTML and locate input fields like:
<input type="hidden" name="user_token" value="abc123..." />
<input type="hidden" name="authenticity_token" value="xyz456..." />Then,
{%user_token%}or{%authenticity_token%}is replaced with the current value dynamically when sending the login request. -
From Meta Tags (Rails / Spring / SPA)
<meta name="csrf-token" content="abc123..." />
<meta name="_csrf" content="xyz456..." />ZAP can map these to a variable placeholder and inject them automatically in the POST body.
-
From Cookies
Some frameworks store CSRF tokens in cookies. For example:
- Django →
csrftoken - Laravel →
XSRF-TOKEN - ASP.NET Core →
.AspNetCore.Antiforgery.*
You can reference them in
headersorbodyTemplateusing ZAP variables:headers:
Cookie: "csrftoken={%cookie:csrftoken%}" - Django →
Recommended bodyTemplate Usage
bodyTemplate: "username={identifier}&password={password}&Login=Login&user_token={%user_token%}"
Or for Rails:
bodyTemplate: "login={identifier}&password={password}&authenticity_token={%authenticity_token%}"
Or for Django:
bodyTemplate: "username={identifier}&password={password}&csrfmiddlewaretoken={%csrfmiddlewaretoken%}"
How to Identify the Correct Token Field
- Open the login page source (Ctrl+U / View Source).
- Search for
type="hidden"in the<form>element. - Note the
nameattribute for the CSRF token. - Use that name in the
bodyTemplatewith{%<name>%}. - Optional: Add the token name under Options → Anti-CSRF Tokens → Add Field Name in ZAP.
Tip: For SPAs, Rails, Django, Laravel, and ASP.NET apps, always check both hidden fields and meta tags for the token.
Example Full Form-Based Login (with token injection)
automation: true
scope:
entryUrls:
- "http://example.com/login"
includePaths:
- "http://example.com.*"
excludePaths:
- "http://example.com/logout"
headers:
Cookie: "PHPSESSID={%cookie:PHPSESSID%}"
authentication:
type: "form"
loginPageUrl: "http://example.com/login"
loginBackendUrl: "http://example.com/login"
bodyTemplate: "username={identifier}&password={password}&Login=Login&user_token={%user_token%}"
pollUrl: "http://example.com/home"
loggedInRegex: "Welcome, admin!"
Summary:
- Use
{%<token_field_name>%}inbodyTemplateto dynamically inject any CSRF or anti-forgery token. - ZAP extracts the current value from hidden inputs, meta tags, or cookies.
- Correct token injection ensures form-based login works for both simple apps (DVWA) and complex apps with redirects or multi-step logins.