Configuration and Authentication
Configuration and Authentication
The following files were used as context for generating this wiki page:
- .github/workflows/ghcr-publish.yml
- .gitignore
- LICENSE
- README.md
- RELEASE_3.0.0.md
- RELEASE_SUMMARY.md
- docs/V3_COMPLETE_GUIDE.md
This page documents all configuration and authentication mechanisms in WSHawk. This includes authentication sequence configuration for stateful WebSocket testing, custom header injection, session-based authentication for specialized tests, and environment-based configuration options.
For information about using the Python API programmatically, see Python API Usage. For CI/CD-specific configuration examples, see CI/CD Integration.
Overview
WSHawk supports multiple configuration and authentication mechanisms to accommodate diverse WebSocket implementations:
| Configuration Type | Use Case | Primary Interface |
|-------------------|----------|-------------------|
| Authentication Sequences | Stateful WebSocket sessions requiring login flows | YAML files loaded via auth_sequence parameter |
| Custom Headers | Bearer tokens, API keys, session cookies | headers dictionary parameter |
| Session Test Auth | Session hijacking test customization | auth_config dictionary in SessionHijackingTester |
| Environment Variables | Runtime behavior customization | PYTHONUNBUFFERED, TIMEOUT, etc. |
| Docker Configuration | Containerized deployment settings | Volume mounts, environment variables, network modes |
Authentication Sequences (YAML)
Purpose and Loading Mechanism
Authentication sequences enable WSHawk to test WebSocket applications that require multi-step login flows before vulnerability testing can begin. The SessionStateMachine class manages these sequences.
Configuration Flow:
graph LR
YAMLFile["YAML Configuration File<br/>auth_sequence.yaml"]
WSHawkV2["WSHawkV2.__init__()<br/>scanner_v2.py:33-34"]
StateMachine["SessionStateMachine<br/>state_machine.py"]
LoadMethod["load_sequence_from_yaml()<br/>state_machine.py"]
WSConnection["WebSocket Connection<br/>Learning Phase"]
YAMLFile -->|"auth_sequence='/path/to/file.yaml'"| WSHawkV2
WSHawkV2 -->|"self.state_machine"| StateMachine
WSHawkV2 -->|"if auth_sequence"| LoadMethod
LoadMethod -->|"Loads and validates"| StateMachine
StateMachine -->|"Executes sequence"| WSConnection
Sources: wshawk/scanner_v2.py:33-63
YAML File Format
Authentication sequences are defined in YAML format with the following structure:
# Example authentication sequence
auth_sequence:
- action: "connect"
message:
type: "handshake"
client_version: "1.0"
- action: "authenticate"
message:
action: "login"
username: "testuser"
password: "testpass"
wait_for_response: true
- action: "subscribe"
message:
action: "subscribe"
channel: "main"
Each step in the sequence supports:
- action: Descriptive name for the step (used in state tracking)
- message: The WebSocket message payload (JSON object)
- wait_for_response: Boolean flag indicating whether to wait for server response
- timeout: Optional timeout in seconds for response waiting
Loading Authentication Sequences
Python API:
from wshawk.scanner_v2 import WSHawkV2
scanner = WSHawkV2(
url="wss://app.example.com/ws",
auth_sequence="/path/to/auth_config.yaml"
)
CLI Usage:
Currently, authentication sequences must be configured programmatically via the Python API. CLI support for external YAML files is planned for future releases.
Sources: wshawk/scanner_v2.py:60-62
Custom Headers Configuration
HTTP Header Injection
Custom headers are passed to the WebSocket connection during the initial HTTP handshake. This is essential for authentication mechanisms that use bearer tokens, API keys, or session cookies.
Header Configuration Flow:
graph TB
UserHeaders["User-Provided Headers<br/>Dict[str, str]"]
WSHawkInit["WSHawkV2.__init__()<br/>headers parameter<br/>scanner_v2.py:33-37"]
ConnectMethod["connect() method<br/>scanner_v2.py:77-85"]
WebSocketsConnect["websockets.connect()<br/>additional_headers parameter<br/>scanner_v2.py:80"]
WSConnection["WebSocket Connection<br/>with custom headers"]
UserHeaders --> WSHawkInit
WSHawkInit -->|"self.headers"| ConnectMethod
ConnectMethod -->|"additional_headers=self.headers"| WebSocketsConnect
WebSocketsConnect --> WSConnection
Sources: wshawk/scanner_v2.py:33-85
Common Header Patterns
| Authentication Type | Header Format | Example |
|--------------------|---------------|---------|
| Bearer Token | Authorization: Bearer <token> | {"Authorization": "Bearer eyJhbG..."} |
| API Key | X-API-Key: <key> | {"X-API-Key": "sk_live_12345"} |
| Session Cookie | Cookie: session=<value> | {"Cookie": "session=abc123; Path=/"} |
| Custom Auth | Custom header name | {"X-Custom-Auth": "value"} |
Configuration Examples
Python API with Bearer Token:
scanner = WSHawkV2(
url="wss://api.example.com/ws",
headers={
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"User-Agent": "WSHawk/2.0.5"
}
)
await scanner.run_intelligent_scan()
Multiple Headers:
scanner = WSHawkV2(
url="wss://secure.example.com/socket",
headers={
"Authorization": "Bearer token123",
"X-API-Key": "sk_test_abcdef",
"X-Client-ID": "client-001",
"Origin": "https://app.example.com"
}
)
Sources: wshawk/scanner_v2.py:33-37, wshawk/scanner_v2.py:77-85
Session Hijacking Test Authentication
SessionHijackingTester Authentication Configuration
The SessionHijackingTester class requires its own authentication configuration to test session security vulnerabilities. This configuration is separate from the main scanner's authentication.
Authentication Configuration Structure:
graph TB
SessionTester["SessionHijackingTester<br/>session_hijacking_tester.py:48-91"]
AuthConfig["auth_config parameter<br/>Dict with auth structure"]
DefaultConfig["Default Configuration<br/>Lines 84-90"]
CustomConfig["Custom Configuration<br/>User-provided"]
GetAuthPayload["_get_auth_payload()<br/>Lines 92-114"]
WSMessage["WebSocket Auth Message<br/>JSON payload"]
SessionTester -->|"Optional"| AuthConfig
AuthConfig --> DefaultConfig
AuthConfig --> CustomConfig
DefaultConfig --> GetAuthPayload
CustomConfig --> GetAuthPayload
GetAuthPayload -->|"json.dumps()"| WSMessage
Sources: wshawk/session_hijacking_tester.py:61-114
Default Authentication Configuration
The default configuration assumes a simple login-based authentication:
{
'action': 'login',
'username_field': 'username',
'password_field': 'password',
'username': 'user1',
'password': 'pass1'
}
This generates the following WebSocket message:
{
"action": "login",
"username": "user1",
"password": "pass1"
}
Sources: wshawk/session_hijacking_tester.py:84-90
Custom Authentication Configuration
Example 1: Custom Field Names
from wshawk.session_hijacking_tester import SessionHijackingTester
tester = SessionHijackingTester(
target_url="ws://localhost:9999",
auth_config={
'action': 'authenticate',
'username_field': 'email',
'password_field': 'pass',
'username': 'test@example.com',
'password': 'secure123'
}
)
This generates:
{
"action": "authenticate",
"email": "test@example.com",
"pass": "secure123"
}
Example 2: Custom Payload Structure
For non-standard authentication flows:
tester = SessionHijackingTester(
target_url="ws://localhost:9999",
auth_config={
'custom_payload': {
"type": "AUTH",
"credentials": {
"user": "testuser",
"token": "abc123"
},
"client_id": "wshawk-tester"
}
}
)
This sends the custom payload directly without field transformation.
Sources: wshawk/session_hijacking_tester.py:92-114
Authentication Payload Generation
The _get_auth_payload() method handles two configuration modes:
flowchart TD
GetAuthPayload["_get_auth_payload(username, password)<br/>session_hijacking_tester.py:92"]
CheckCustom{"'custom_payload'<br/>in auth_config?"}
UseCustom["Return custom_payload<br/>Lines 94-95"]
BuildPayload["Build from fields<br/>Lines 97-114"]
CheckAction{"'action' field<br/>exists?"}
ActionSeparate["action as separate field<br/>Lines 107-112"]
ActionAsKey["action as boolean key<br/>Lines 100-104"]
JSONDumps["json.dumps(payload)<br/>Line 114"]
GetAuthPayload --> CheckCustom
CheckCustom -->|"Yes"| UseCustom
CheckCustom -->|"No"| BuildPayload
BuildPayload --> CheckAction
CheckAction -->|"Yes"| ActionSeparate
CheckAction -->|"No"| ActionAsKey
ActionSeparate --> JSONDumps
ActionAsKey --> JSONDumps
UseCustom --> JSONDumps
Sources: wshawk/session_hijacking_tester.py:92-114
Environment Variables
Supported Environment Variables
WSHawk respects standard Python and container environment variables:
| Variable | Purpose | Default | Example |
|----------|---------|---------|---------|
| PYTHONUNBUFFERED | Disable Python output buffering (useful for real-time logs) | 0 | PYTHONUNBUFFERED=1 |
| TIMEOUT | Custom timeout for WebSocket operations | 3.0 | TIMEOUT=30 |
Usage in Docker
Environment variables can be set in multiple ways when using Docker:
Command Line:
docker run --rm -e PYTHONUNBUFFERED=1 -e TIMEOUT=30 rothackers/wshawk ws://target.com
Docker Compose:
services:
wshawk:
image: rothackers/wshawk:latest
environment:
- PYTHONUNBUFFERED=1
- TIMEOUT=30
Sources: docker-compose.yml:17-18, docs/DOCKER.md:112-118
Docker-Specific Configuration
Volume Mounting for Configuration Files
To use YAML authentication sequences or save configuration files in Docker:
# Mount configuration directory
docker run --rm \
-v $(pwd)/config:/app/config \
-v $(pwd)/reports:/app/reports \
rothackers/wshawk ws://target.com
Directory Structure:
./config/
├── auth_sequence.yaml
└── custom_payloads.txt
./reports/
└── wshawk_report_*.html
Sources: docs/DOCKER.md:56-63
Network Configuration
Host Network Mode (for local testing):
docker run --rm --network host rothackers/wshawk ws://localhost:8765
Custom Network:
docker network create wshawk-net
docker run --rm --network wshawk-net rothackers/wshawk ws://target.com
Docker Compose Network Configuration:
services:
wshawk:
network_mode: host # Access localhost services
# OR
networks:
- wshawk-network
networks:
wshawk-network:
driver: bridge
Sources: docs/DOCKER.md:66-70, docs/DOCKER.md:132-143, docker-compose.yml:8-35
User and Permission Configuration
The Docker image runs as non-root user wshawk:1000 by default. To avoid permission issues with volume mounts:
# Run as current user
docker run --rm --user $(id -u):$(id -g) \
-v $(pwd)/reports:/app/reports \
rothackers/wshawk ws://target.com
Sources: docs/DOCKER.md:169-174, docs/DOCKER.md:196-201
Configuration Precedence and Override
Configuration Loading Order
graph TB
DefaultConfig["Default Configuration<br/>Hard-coded in classes"]
EnvVars["Environment Variables<br/>OS-level settings"]
ConstructorParams["Constructor Parameters<br/>Python API / CLI args"]
YAMLFiles["YAML Configuration Files<br/>auth_sequence parameter"]
RuntimeOverride["Runtime Overrides<br/>Method parameters"]
DefaultConfig --> EnvVars
EnvVars --> ConstructorParams
ConstructorParams --> YAMLFiles
YAMLFiles --> RuntimeOverride
DefaultConfig -.->|"Lowest Priority"| P1[ ]
RuntimeOverride -.->|"Highest Priority"| P2[ ]
style P1 fill:none,stroke:none
style P2 fill:none,stroke:none
Example: Header Configuration Override
# 1. Default headers (empty)
scanner = WSHawkV2(url="ws://target.com")
# headers = {}
# 2. Constructor override
scanner = WSHawkV2(
url="ws://target.com",
headers={"Authorization": "Bearer token1"}
)
# headers = {"Authorization": "Bearer token1"}
# 3. Runtime modification (not directly supported, requires reconnection)
scanner.headers["X-Custom"] = "value"
ws = await scanner.connect() # Uses updated headers
Sources: wshawk/scanner_v2.py:33-85
Complete Configuration Example
Full Python API Configuration
import asyncio
from wshawk.scanner_v2 import WSHawkV2
async def main():
scanner = WSHawkV2(
# Target WebSocket URL
url="wss://api.example.com/ws",
# Custom HTTP headers for initial handshake
headers={
"Authorization": "Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"X-API-Key": "sk_live_12345",
"User-Agent": "WSHawk/2.0.5 Security Scanner",
"Origin": "https://app.example.com"
},
# Authentication sequence (YAML file path)
auth_sequence="./config/auth_sequence.yaml",
# Rate limiting (requests per second)
max_rps=10
)
# Configure optional features
scanner.use_headless_browser = True # Enable Playwright XSS verification
scanner.use_oast = True # Enable OAST for blind vulnerabilities
# Run comprehensive scan
results = await scanner.run_intelligent_scan()
print(f"Found {len(results)} vulnerabilities")
if __name__ == "__main__":
asyncio.run(main())
Session Hijacking Test Configuration
from wshawk.session_hijacking_tester import SessionHijackingTester
tester = SessionHijackingTester(
target_url="ws://localhost:9999",
auth_config={
'action': 'login',
'username_field': 'email',
'password_field': 'password',
'username': 'test@example.com',
'password': 'secure123'
}
)
results = await tester.run_all_tests()
Sources: wshawk/scanner_v2.py:28-76, wshawk/session_hijacking_tester.py:48-91
Configuration Best Practices
Security Considerations
| Practice | Rationale | Implementation |
|----------|-----------|----------------|
| Never hardcode credentials | Prevents credential leakage in version control | Use environment variables or external config files |
| Use environment-specific configs | Different credentials for dev/staging/prod | Separate YAML files per environment |
| Rotate authentication tokens | Limits exposure window | Update headers/configs before each scan |
| Restrict file permissions | Prevents unauthorized config access | chmod 600 auth_sequence.yaml |
Configuration File Management
# Recommended directory structure
.
├── config/
│ ├── prod_auth.yaml # Production authentication
│ ├── staging_auth.yaml # Staging authentication
│ └── dev_auth.yaml # Development authentication
├── reports/ # Scan output
└── .gitignore # Exclude config/ from version control
Example .gitignore:
config/
reports/
*.yaml
Sources: Project best practices, standard security guidelines
Troubleshooting
Common Configuration Issues
| Issue | Symptom | Solution |
|-------|---------|----------|
| Authentication sequence not loading | TypeError: load_sequence_from_yaml() | Ensure YAML file path is absolute or relative to execution directory |
| Headers not applied | Authentication fails despite correct credentials | Verify headers are passed to WSHawkV2.__init__(), not connect() |
| Docker volume permissions | Cannot write reports | Use --user $(id -u):$(id -g) or adjust host directory permissions |
| Session test auth fails | Tests skip or error | Verify auth_config structure matches server expectations |
Debug Configuration Loading
To verify configuration is loaded correctly, enable verbose logging:
from wshawk.logger import setup_logging
logger = setup_logging(verbose=True, log_file="wshawk_debug.log")
scanner = WSHawkV2(
url="ws://target.com",
headers={"Authorization": "Bearer token"}
)
# Check logs for header application
Sources: wshawk/logger.py:37-70
Configuration Reference Tables
WSHawkV2 Constructor Parameters
| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| url | str | Required | WebSocket URL (ws:// or wss://) |
| headers | Optional[Dict] | None | Custom HTTP headers for handshake |
| auth_sequence | Optional[str] | None | Path to YAML authentication sequence file |
| max_rps | int | 10 | Maximum requests per second (rate limiting) |
Sources: wshawk/scanner_v2.py:33-35
SessionHijackingTester Auth Config Fields
| Field | Type | Required | Description |
|-------|------|----------|-------------|
| action | str | No | Action type for auth message |
| username_field | str | No | Field name for username (default: "username") |
| password_field | str | No | Field name for password (default: "password") |
| username | str | No | Username value (default: "user1") |
| password | str | No | Password value (default: "pass1") |
| custom_payload | Dict | No | Complete custom authentication payload |
Sources: wshawk/session_hijacking_tester.py:84-114
Sources: wshawk/scanner_v2.py:1-681, wshawk/session_hijacking_tester.py:1-573, wshawk/logger.py:1-71, docker-compose.yml:1-36, docs/DOCKER.md:1-240