DAST Best Practices: Testing Running Applications for Security Vulnerabilities

Master Dynamic Application Security Testing (DAST) with OWASP ZAP. Learn authentication strategies, scope management, CI/CD integration, and how to complement SAST for comprehensive security coverage.

DAST vs SAST: Complementary Approaches

While SAST analyzes source code without execution, DAST tests the running application from an attacker's perspective:

Aspect SAST (Static) DAST (Dynamic)
Testing Phase Development (before runtime) Staging/Production (runtime)
Access Required Source code Running application URL
Finds Code patterns, potential bugs Actual exploitable vulnerabilities
False Positives Higher (context missing) Lower (validates exploitability)
Coverage All code paths Only accessible endpoints
💡 Best Practice:

Use SAST during development to catch issues early, then DAST in staging to validate the deployed application. Together they provide comprehensive coverage.

Choosing a DAST Tool

Popular DAST tools for different use cases:

OWASP ZAP (Recommended)

Pros: Free, open-source, extensive features, CI/CD friendly

Cons: Steeper learning curve, requires configuration

Best for: Teams wanting full control and customization

Burp Suite (Professional)

Pros: Powerful scanning, excellent UI, active community

Cons: Expensive ($399/year), manual focus

Best for: Security professionals doing manual testing

Nuclei

Pros: Fast, template-based, easy CI/CD integration

Cons: Limited crawling, requires template management

Best for: Known vulnerability scanning at scale

Setting Up OWASP ZAP

Installation

Docker (Recommended for CI/CD)
# Pull the latest ZAP Docker image
docker pull owasp/zap2docker-stable

# Run interactive ZAP with WebSwing UI
docker run -u zap -p 8080:8080 -p 8090:8090 \
  -i owasp/zap2docker-stable zap-webswing.sh

Baseline Scan

Start with a quick baseline scan to identify low-hanging fruit:

ZAP Baseline Scan
# Basic scan (5-10 minutes)
docker run --rm \
  -v $(pwd):/zap/wrk/:rw \
  owasp/zap2docker-stable zap-baseline.py \
  -t https://staging.yourdomain.com \
  -r zap-baseline-report.html \
  -J zap-baseline-report.json

# With authentication (context file)
docker run --rm \
  -v $(pwd):/zap/wrk/:rw \
  owasp/zap2docker-stable zap-baseline.py \
  -t https://staging.yourdomain.com \
  -n /zap/wrk/context.context \
  -U testuser \
  -r report.html

Full Scan

Comprehensive scan with active vulnerability testing (30-60+ minutes):

ZAP Full Scan
docker run --rm \
  -v $(pwd):/zap/wrk/:rw \
  owasp/zap2docker-stable zap-full-scan.py \
  -t https://staging.yourdomain.com \
  -r zap-full-report.html \
  -J zap-full-report.json \
  -x zap-full-report.xml

Authentication Strategies

Method 1: Form-Based Authentication

Create a ZAP context file for web applications with login forms:

context.context (JSON)
{
  "context": {
    "name": "Staging Environment",
    "urls": ["https://staging.yourdomain.com.*"],
    "auth": {
      "type": "form",
      "loginUrl": "https://staging.yourdomain.com/login",
      "loginRequestData": "username={%username%}&password={%password%}",
      "usernameParameter": "username",
      "passwordParameter": "password",
      "loggedInIndicator": "\\QLogout\\E",
      "loggedOutIndicator": "\\Q
\\E" }, "users": [{ "name": "testuser", "credentials": { "username": "test@example.com", "password": "TestPassword123!" } }] } }

Method 2: API Token Authentication

For REST APIs with bearer tokens:

ZAP Script-Based Auth
// Authentication script (JavaScript)
function authenticate(helper, paramsValues, credentials) {
    var msg = helper.prepareMessage();
    msg.setRequestHeader("Authorization: Bearer " + paramsValues.get("token"));
    helper.sendAndReceive(msg);
    return msg;
}

function getRequiredParamsNames() {
    return ["token"];
}

function getOptionalParamsNames() {
    return [];
}

Method 3: Session Cookies

Reuse authenticated session cookies:

# Get session cookie manually or via script
curl -c cookies.txt -X POST https://staging.yourdomain.com/login \
  -d "username=test@example.com&password=TestPassword123!"

# Run ZAP with cookies
docker run --rm \
  -v $(pwd):/zap/wrk/:rw \
  owasp/zap2docker-stable zap-baseline.py \
  -t https://staging.yourdomain.com \
  --hook=/zap/wrk/cookie-script.py

Scope Management

Include/Exclude Rules

Prevent scanning sensitive or third-party endpoints:

.zapignore (Create in project root)
# Exclude admin panels from active scans
https://staging.yourdomain.com/admin/.*

# Exclude third-party integrations
https://staging.yourdomain.com/webhooks/stripe/.*

# Exclude logout (prevents session termination)
https://staging.yourdomain.com/logout

# Exclude heavy operations
https://staging.yourdomain.com/api/reports/generate.*

robots.txt Compliance

Respect robots.txt to avoid scanning disallowed paths:

docker run --rm \
  -v $(pwd):/zap/wrk/:rw \
  owasp/zap2docker-stable zap-baseline.py \
  -t https://staging.yourdomain.com \
  --config spider.parseRobotsTxt=true

CI/CD Integration

GitHub Actions Workflow

.github/workflows/dast-scan.yml
name: DAST Scan

on:
  schedule:
    # Run every night at 2 AM UTC
    - cron: '0 2 * * *'
  workflow_dispatch:  # Manual trigger

jobs:
  zap-scan:
    runs-on: ubuntu-latest
    
    steps:
      - name: Checkout
        uses: actions/checkout@v4
      
      - name: Wait for deployment
        run: |
          # Ensure staging is ready
          for i in {1..10}; do
            if curl -f -s https://staging.yourdomain.com/health; then
              echo "✅ Staging is ready"
              exit 0
            fi
            echo "⏳ Waiting for staging..."
            sleep 10
          done
          exit 1
      
      - name: Run ZAP Baseline Scan
        uses: zaproxy/action-baseline@v0.7.0
        with:
          target: 'https://staging.yourdomain.com'
          rules_file_name: '.zap/rules.tsv'
          cmd_options: '-a -j'  # AJAX spider, JSON report
      
      - name: Upload ZAP Report
        uses: actions/upload-artifact@v3
        if: always()
        with:
          name: zap-scan-report
          path: report_html.html
      
      - name: Check for High/Critical Issues
        run: |
          HIGH_COUNT=$(jq '[.site[].alerts[] | select(.riskcode >= "2")] | length' report_json.json)
          
          if [ "$HIGH_COUNT" -gt "0" ]; then
            echo "❌ Found $HIGH_COUNT high/critical vulnerabilities!"
            exit 1
          fi

Custom Rules Configuration

Create .zap/rules.tsv to customize alerting thresholds:

.zap/rules.tsv
# Format: rule_id	threshold	[IGNORE, WARN, FAIL]
10021	IGNORE	# X-Content-Type-Options header (handled by CDN)
10020	WARN	# X-Frame-Options (non-critical for API)
10038	FAIL	# Content Security Policy missing
90022	FAIL	# Application Error Disclosure
40012	FAIL	# Cross Site Scripting (Reflected)
40014	FAIL	# Cross Site Scripting (Persistent)

Interpreting Results

Risk Levels

Level Description Action
High Directly exploitable (SQLi, XSS, Auth bypass) Fix immediately, block deployment
Medium Requires conditions (CSRF, session issues) Fix in current sprint
Low Informational leaks, missing headers Backlog, fix when convenient
Informational Best practices, no direct risk Consider for hardening

Common False Positives

  • X-Frame-Options on APIs: Not needed for non-browser endpoints
  • Cookie without SameSite: May be intentional for OAuth flows
  • SQL injection in base64: Often a decoding artifact, verify manually
  • XSS in JSON responses: Safe if Content-Type is application/json

Advanced Techniques

AJAX Spider

For single-page applications (React, Vue, Angular):

docker run --rm \
  -v $(pwd):/zap/wrk/:rw \
  owasp/zap2docker-stable zap-baseline.py \
  -t https://staging.yourdomain.com \
  -a  # Enable AJAX spider
  --config spider.maxDuration=10 \
  --config ajaxSpider.clickElemsOnce=true

API Scanning with OpenAPI Spec

Import OpenAPI/Swagger spec for comprehensive API coverage:

docker run --rm \
  -v $(pwd):/zap/wrk/:rw \
  owasp/zap2docker-stable zap-api-scan.py \
  -t https://staging.yourdomain.com/api/swagger.json \
  -f openapi \
  -r api-scan-report.html

Authenticated API Testing

# Generate API token
TOKEN=$(curl -X POST https://staging.yourdomain.com/api/auth \
  -d '{"username":"test@example.com","password":"TestPassword123!"}' \
  | jq -r '.token')

# Run ZAP with token in headers
docker run --rm \
  -v $(pwd):/zap/wrk/:rw \
  -e "TOKEN=$TOKEN" \
  owasp/zap2docker-stable zap-api-scan.py \
  -t https://staging.yourdomain.com/api/swagger.json \
  -f openapi \
  --config replacer.full_list(0).description=auth \
  --config replacer.full_list(0).enabled=true \
  --config replacer.full_list(0).matchtype=REQ_HEADER \
  --config replacer.full_list(0).matchstr=Authorization \
  --config replacer.full_list(0).replacement="Bearer $TOKEN"

Performance Optimization

Parallel Scanning

Split scans by route prefix for faster execution:

# Scan /api routes
docker run --rm -v $(pwd):/zap/wrk/:rw \
  owasp/zap2docker-stable zap-baseline.py \
  -t https://staging.yourdomain.com/api \
  -r api-report.html &

# Scan /admin routes
docker run --rm -v $(pwd):/zap/wrk/:rw \
  owasp/zap2docker-stable zap-baseline.py \
  -t https://staging.yourdomain.com/admin \
  -r admin-report.html &

wait  # Wait for both to finish

Scan Scheduling

  • Baseline scans: Every deployment (5-10 min)
  • Full scans: Nightly or weekly (30-60 min)
  • API scans: On API spec changes (10-20 min)

Best Practices Checklist

Troubleshooting

Scans Timing Out

  • Increase timeout: --config connection.timeoutInSecs=300
  • Reduce spider depth: --config spider.maxDepth=3
  • Disable heavy scans: Add -config scanner.strength=LOW

Authentication Failing

  • Verify logged-in indicator regex matches actual response
  • Check if CSRF tokens are required (use ZAP anti-CSRF token handling)
  • Use network inspection (browser DevTools) to capture exact login request
  • Try session cookie injection instead of form-based auth

Too Many False Positives

  • Use rules.tsv to IGNORE specific rule IDs for your context
  • Add regex patterns to exclude endpoints from active scanning
  • Start with -config scanner.attackStrength=LOW

Next Steps

You're now equipped to implement DAST scanning! Continue your security journey:

💡 Need Help with DAST?

ElevatedIQ offers automated DAST scanning with custom authentication scripts, false positive filtering, and 24/7 monitoring. Get in touch to secure your running applications.