11 KiB
ZAP API Security Testing Guide
Advanced guide for testing REST, GraphQL, SOAP, and WebSocket APIs using OWASP ZAP.
Overview
Modern applications rely heavily on APIs. This guide covers comprehensive API security testing patterns using ZAP's API scanning capabilities.
API Types Supported
- REST APIs (JSON, XML)
- GraphQL APIs
- SOAP APIs (WSDL-based)
- gRPC APIs
- WebSocket APIs
REST API Testing
Testing with OpenAPI/Swagger Specification
Best Practice: Always use API specifications when available for complete coverage.
# Basic OpenAPI scan
docker run -v $(pwd):/zap/wrk/:rw -t zaproxy/zap-stable zap-api-scan.py \
-t https://api.example.com \
-f openapi \
-d /zap/wrk/openapi.yaml \
-r /zap/wrk/api-report.html
Testing Without Specification (Spider-Based)
When no specification is available:
# Use standard spider with API context
docker run -v $(pwd):/zap/wrk/:rw -t zaproxy/zap-stable zap-full-scan.py \
-t https://api.example.com \
-r /zap/wrk/api-report.html \
-z "-config spider.parseComments=true -config spider.parseRobotsTxt=true"
Authentication Patterns
Bearer Token (JWT)
# Obtain token first
TOKEN=$(curl -X POST https://api.example.com/auth/login \
-H "Content-Type: application/json" \
-d '{"username":"testuser","password":"password"}' \
| jq -r '.access_token')
# Scan with authentication
python3 scripts/zap_api_scan.py \
--target https://api.example.com \
--format openapi \
--spec openapi.yaml \
--header "Authorization: Bearer $TOKEN"
API Key Authentication
# API key in header
python3 scripts/zap_api_scan.py \
--target https://api.example.com \
--format openapi \
--spec openapi.yaml \
--header "X-API-Key: your-api-key-here"
# API key in query parameter
python3 scripts/zap_api_scan.py \
--target https://api.example.com?api_key=your-api-key \
--format openapi \
--spec openapi.yaml
Common REST API Vulnerabilities
1. Broken Object Level Authorization (BOLA)
Detection: Test access to resources belonging to other users.
Manual Test:
# Request resource with different user IDs
curl -H "Authorization: Bearer $USER1_TOKEN" \
https://api.example.com/users/123/profile
curl -H "Authorization: Bearer $USER2_TOKEN" \
https://api.example.com/users/123/profile # Should be denied
ZAP Configuration: Add authorization test scripts to detect BOLA.
2. Mass Assignment
Detection: Send additional fields not in API specification.
Test Payload:
{
"username": "testuser",
"email": "test@example.com",
"is_admin": true, # Unauthorized field
"role": "admin" # Unauthorized field
}
3. Rate Limiting
Detection: Send multiple requests rapidly.
# Test rate limiting
for i in {1..100}; do
curl https://api.example.com/endpoint -H "Authorization: Bearer $TOKEN"
done
Expected: HTTP 429 (Too Many Requests) after threshold.
GraphQL API Testing
Testing with GraphQL Schema
# Scan GraphQL endpoint with schema
docker run -v $(pwd):/zap/wrk/:rw -t zaproxy/zap-stable zap-api-scan.py \
-t https://api.example.com/graphql \
-f graphql \
-d /zap/wrk/schema.graphql \
-r /zap/wrk/graphql-report.html
GraphQL Introspection
Check if introspection is enabled:
curl -X POST https://api.example.com/graphql \
-H "Content-Type: application/json" \
-d '{"query": "{ __schema { types { name } } }"}'
Security Note: Disable introspection in production.
GraphQL-Specific Vulnerabilities
1. Query Depth/Complexity Attacks
Malicious Query:
query {
user {
posts {
comments {
author {
posts {
comments {
author {
# ... deeply nested
}
}
}
}
}
}
}
}
Mitigation: Implement query depth/complexity limits.
2. Batch Query Attacks
Malicious Query:
query {
user1: user(id: 1) { name email }
user2: user(id: 2) { name email }
# ... repeated hundreds of times
user500: user(id: 500) { name email }
}
Mitigation: Limit batch query size.
3. Field Suggestions
When introspection is disabled, test field suggestions:
query {
user {
nam # Intentional typo to trigger suggestions
}
}
SOAP API Testing
Testing with WSDL
# SOAP API scan with WSDL
docker run -v $(pwd):/zap/wrk/:rw -t zaproxy/zap-stable zap-api-scan.py \
-t https://api.example.com/soap \
-f soap \
-d /zap/wrk/service.wsdl \
-r /zap/wrk/soap-report.html
SOAP-Specific Vulnerabilities
1. XML External Entity (XXE)
Test Payload:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "file:///etc/passwd">]>
<soap:Envelope>
<soap:Body>
<login>
<username>&xxe;</username>
</login>
</soap:Body>
</soap:Envelope>
2. XML Injection
Test Payload:
<username>admin</username><role>admin</role></user><user><username>attacker</username>
WebSocket Testing
Manual WebSocket Testing
ZAP can intercept WebSocket traffic:
- Configure browser proxy to ZAP
- Connect to WebSocket endpoint
- Review messages in ZAP's WebSocket tab
- Manually craft malicious messages
Common WebSocket Vulnerabilities
- Message Injection: Inject malicious payloads in WebSocket messages
- Authentication Bypass: Test if authentication is required for WebSocket connections
- Message Tampering: Modify messages in transit
API Security Testing Checklist
Authentication & Authorization
- Test unauthenticated access to protected endpoints
- Test authorization bypass (access other users' data)
- Test JWT token validation (expiration, signature)
- Test API key validation
- Test role-based access control (RBAC)
Input Validation
- Test SQL injection in parameters
- Test NoSQL injection (MongoDB, etc.)
- Test command injection
- Test XML injection (for SOAP APIs)
- Test mass assignment vulnerabilities
- Test parameter pollution
Rate Limiting & DoS
- Verify rate limiting is enforced
- Test resource exhaustion (large payloads)
- Test query complexity limits (GraphQL)
- Test batch request limits
Data Exposure
- Check for sensitive data in responses
- Test verbose error messages
- Verify PII is properly protected
- Check for data leakage in logs
Transport Security
- Verify HTTPS is enforced
- Test TLS configuration (strong ciphers only)
- Check certificate validation
- Verify HSTS header is set
Business Logic
- Test state manipulation
- Test payment flow manipulation
- Test workflow bypass
- Test negative values/amounts
ZAP Automation for API Testing
Automation Framework Configuration
api_automation.yaml:
env:
contexts:
- name: API-Context
urls:
- https://api.example.com
includePaths:
- https://api.example.com/.*
authentication:
method: header
parameters:
header: Authorization
value: "Bearer ${API_TOKEN}"
jobs:
- type: openapi
parameters:
apiFile: /zap/wrk/openapi.yaml
apiUrl: https://api.example.com
targetUrl: https://api.example.com
context: API-Context
- type: passiveScan-wait
- type: activeScan
parameters:
context: API-Context
policy: API-Scan-Policy
user: api-user
- type: report
parameters:
template: traditional-html
reportDir: /zap/wrk/
reportFile: api-security-report.html
reportTitle: API Security Assessment
Run:
export API_TOKEN="your-token-here"
docker run -v $(pwd):/zap/wrk/:rw -t zaproxy/zap-stable \
zap.sh -cmd -autorun /zap/wrk/api_automation.yaml
Custom API Scan Policies
Create API-Optimized Scan Policy
Disable irrelevant checks for APIs:
- Disable DOM XSS checks (no browser context)
- Disable CSRF checks (stateless APIs)
- Enable injection checks (SQL, NoSQL, Command)
- Enable authentication/authorization checks
See assets/scan_policy_api.policy for pre-configured policy.
API Testing Tools Integration
Postman Integration
Export Postman collection to OpenAPI:
# Use Postman's built-in export or newman
newman run collection.json --export-collection openapi.yaml
cURL to OpenAPI Conversion
Use tools like curl-to-openapi to generate specs from cURL commands.
Common API Testing Patterns
Pattern 1: CRUD Operation Testing
Test all CRUD operations for each resource:
# CREATE
curl -X POST https://api.example.com/users \
-H "Authorization: Bearer $TOKEN" \
-d '{"username":"testuser"}'
# READ
curl https://api.example.com/users/123 \
-H "Authorization: Bearer $TOKEN"
# UPDATE
curl -X PUT https://api.example.com/users/123 \
-H "Authorization: Bearer $TOKEN" \
-d '{"username":"updated"}'
# DELETE
curl -X DELETE https://api.example.com/users/123 \
-H "Authorization: Bearer $TOKEN"
Pattern 2: Multi-User Testing
Test with different user roles:
# Admin user
export ADMIN_TOKEN="admin-token"
python3 scripts/zap_api_scan.py --target https://api.example.com \
--header "Authorization: Bearer $ADMIN_TOKEN"
# Regular user
export USER_TOKEN="user-token"
python3 scripts/zap_api_scan.py --target https://api.example.com \
--header "Authorization: Bearer $USER_TOKEN"
Pattern 3: Versioned API Testing
Test all API versions:
# v1
python3 scripts/zap_api_scan.py --target https://api.example.com/v1 \
--spec openapi-v1.yaml
# v2
python3 scripts/zap_api_scan.py --target https://api.example.com/v2 \
--spec openapi-v2.yaml
Troubleshooting API Scans
Issue: OpenAPI Import Fails
Solution: Validate OpenAPI spec:
# Use Swagger Editor or openapi-validator
npx @apidevtools/swagger-cli validate openapi.yaml
Issue: Authentication Not Working
Solution: Test authentication manually first:
curl -v https://api.example.com/protected-endpoint \
-H "Authorization: Bearer $TOKEN"
Issue: Rate Limiting During Scan
Solution: Reduce scan speed:
docker run -t zaproxy/zap-stable zap-api-scan.py \
-t https://api.example.com -f openapi -d /zap/wrk/spec.yaml \
-z "-config scanner.delayInMs=1000"