Skip to main content

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 as loginPageUrl.
  • 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

MethodWhen to UseNotes
AutodetectSimple apps like DVWA✅ ZAP detects login success from response; works for small, predictable forms.
Poll URLComplex 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

FieldMeaning
automationMust be true.
scope.entryUrlsStarting URL for crawling; must point to login page.
scope.includePathsRegex patterns for URLs to include in scan.
scope.excludePathsRegex patterns for URLs to exclude (logout, static assets).
headersSession cookies or business headers.
authentication.typeMust be form for form-based login.
loginPageUrlLogin page URL.
loginBackendUrlForm submission URL.
bodyTemplatePOST body template with username, password, and CSRF tokens.
pollUrlOptional endpoint to verify login.
loggedInRegexRegex/keyword to confirm successful authentication.

5. Form-Based Authentication Scenarios

ScenarioSetupNotes
Simple apps (DVWA)AutodetectWorks for small lab apps; ZAP detects login success automatically.
Apps with dynamic CSRF tokensPoll URL + bodyTemplateRecommended; must include CSRF token in bodyTemplate and add field name in ZAP.
Apps with 302 redirects or multi-stepPoll URL verificationLogin response may be empty; poll URL ensures session is valid.

6. Special Considerations

  1. Dynamic CSRF Token Extraction

    • Common field names:

      FrameworkHidden Field NameMeta / Header / Cookie Name
      Railsauthenticity_tokencsrf-token / X-CSRF-Token
      Djangocsrfmiddlewaretokencsrftoken / X-CSRFToken
      ASP.NET__RequestVerificationToken.AspNetCore.* / RequestVerificationToken
      Laravel_token / csrf_tokenXSRF-TOKEN / X-XSRF-TOKEN
      Spring_csrfX-CSRF-TOKEN / XSRF-TOKEN
      WordPress_wpnoncen/a
      DVWA/PHPuser_token / token / csrfn/a
    • Use {%user_token%} in bodyTemplate to inject dynamically.

    • Add field names under Options → Anti CSRF Tokens → Add Field Name in ZAP.

  2. Poll URL Verification

    • Use if login page returns redirect or empty body.
    • loggedInRegex should match text on the landing page after login.
  3. Headers

    • Include any business headers or cookies required for authenticated session.

7. Example Configurations

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 / AppBody Template Example
DVWA / Generic PHPusername={identifier}&password={password}&Login=Login&user_token={%user_token%}
Rails / GitHublogin={identifier}&password={password}&authenticity_token={%authenticity_token%}
Djangousername={identifier}&password={password}&csrfmiddlewaretoken={%csrfmiddlewaretoken%}
ASP.NET / MVCusername={identifier}&password={password}&__RequestVerificationToken={%__RequestVerificationToken%}
Laravel / Symfonyemail={identifier}&password={password}&_token={%_token%}
WordPresslog={identifier}&pwd={password}&_wpnonce={%_wpnonce%}

How ZAP Extracts Tokens

  1. 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.

  2. 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.

  3. 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 headers or bodyTemplate using ZAP variables:

    headers:
    Cookie: "csrftoken={%cookie:csrftoken%}"

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

  1. Open the login page source (Ctrl+U / View Source).
  2. Search for type="hidden" in the <form> element.
  3. Note the name attribute for the CSRF token.
  4. Use that name in the bodyTemplate with {%<name>%}.
  5. 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>%} in bodyTemplate to 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.