# 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.
```bash
# 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:
```bash
# 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)
```bash
# 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
```bash
# 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:**
```bash
# 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:**
```json
{
"username": "testuser",
"email": "test@example.com",
"is_admin": true, # Unauthorized field
"role": "admin" # Unauthorized field
}
```
#### 3. Rate Limiting
**Detection:** Send multiple requests rapidly.
```bash
# 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
```bash
# 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:**
```bash
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:**
```graphql
query {
user {
posts {
comments {
author {
posts {
comments {
author {
# ... deeply nested
}
}
}
}
}
}
}
}
```
**Mitigation:** Implement query depth/complexity limits.
#### 2. Batch Query Attacks
**Malicious Query:**
```graphql
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:
```graphql
query {
user {
nam # Intentional typo to trigger suggestions
}
}
```
## SOAP API Testing
### Testing with WSDL
```bash
# 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
]>
&xxe;
```
#### 2. XML Injection
**Test Payload:**
```xml
adminadminattacker
```
## WebSocket Testing
### Manual WebSocket Testing
ZAP can intercept WebSocket traffic:
1. Configure browser proxy to ZAP
2. Connect to WebSocket endpoint
3. Review messages in ZAP's WebSocket tab
4. 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`:
```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:
```bash
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:
```bash
# 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:
```bash
# 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:
```bash
# 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:
```bash
# 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:
```bash
# Use Swagger Editor or openapi-validator
npx @apidevtools/swagger-cli validate openapi.yaml
```
### Issue: Authentication Not Working
**Solution:** Test authentication manually first:
```bash
curl -v https://api.example.com/protected-endpoint \
-H "Authorization: Bearer $TOKEN"
```
### Issue: Rate Limiting During Scan
**Solution:** Reduce scan speed:
```bash
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"
```
## Additional Resources
- [OWASP API Security Top 10](https://owasp.org/www-project-api-security/)
- [REST API Security Cheat Sheet](https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html)
- [GraphQL Security](https://graphql.org/learn/authorization/)
- [ZAP OpenAPI Add-on](https://www.zaproxy.org/docs/desktop/addons/openapi-support/)