Authentication and API Keys

Authentication and API Keys

The following files were used as context for generating this wiki page:

Purpose and Scope

This page documents the authentication mechanisms available in the WSHawk Web Management Dashboard, including password-based authentication for browser access and API key authentication for programmatic access. For information about launching the dashboard and configuring ports, see Dashboard Overview and Launch. For REST API endpoint reference, see REST API Reference.

Overview

The WSHawk Web Management Dashboard supports two independent authentication mechanisms:

| Mechanism | Use Case | Configuration Method | Access Type | |-----------|----------|---------------------|-------------| | Password Authentication | Interactive browser login | WSHAWK_WEB_PASSWORD | Web UI + API | | API Key Authentication | Programmatic/headless access | WSHAWK_API_KEY | API only |

Both mechanisms use SHA-256 hashing with salted storage to protect credentials. If neither is configured, the dashboard operates in open mode (suitable only for local testing on localhost).

Sources: README.md:121-136


Web Dashboard Password Authentication

Configuration

The web dashboard password is configured via the WSHAWK_WEB_PASSWORD environment variable. This password protects both the web UI and the REST API endpoints.

# Set password before launching dashboard
export WSHAWK_WEB_PASSWORD='your-strong-password'
wshawk --web --port 5000

When the password is set, all access to the dashboard requires authentication through the login page at /login.

Password Hashing Implementation

The dashboard implements SHA-256 hashing with salt for password storage:

  1. Password Reception: Plain text password received via POST to /login
  2. Salt Generation: A random salt is generated or retrieved from persistent storage
  3. Hash Computation: SHA-256(password + salt) is computed
  4. Comparison: Computed hash is compared with stored hash

The actual password is never stored in plaintext or logged.

Authentication Flow Diagram

sequenceDiagram
    participant User as "Browser User"
    participant Login as "/login Endpoint"
    participant Auth as "Authentication Module"
    participant Session as "Session Store"
    participant DB as "scans.db<br/>(SQLite)"
    
    User->>Login: "POST /login<br/>{password: 'user_password'}"
    Login->>Auth: "validate_password()"
    Auth->>DB: "SELECT salt FROM auth_config"
    DB-->>Auth: "salt_value"
    Auth->>Auth: "compute_hash = SHA256(password + salt)"
    Auth->>DB: "SELECT password_hash FROM auth_config"
    DB-->>Auth: "stored_hash"
    Auth->>Auth: "compare(compute_hash, stored_hash)"
    
    alt Authentication Success
        Auth-->>Session: "create_session(user_id)"
        Session-->>Login: "session_cookie"
        Login-->>User: "302 Redirect to /dashboard<br/>Set-Cookie: session_id"
    else Authentication Failure
        Auth-->>Login: "401 Unauthorized"
        Login-->>User: "401 Error: Invalid password"
    end

Sources: README.md:121-127, RELEASE_3.0.0.md:18, docs/V3_COMPLETE_GUIDE.md:299-302


API Key Authentication

Configuration

API keys provide a method for programmatic access to the REST API without browser-based login. This is essential for CI/CD integration and automated workflows.

# Set API key for programmatic access
export WSHAWK_API_KEY='your-api-key-here'

# Use with curl
curl -H "X-API-Key: your-api-key-here" \
  http://localhost:5000/api/scans

Alternatively, the API key can be passed as a command-line flag when launching the dashboard:

wshawk --web --api-key 'your-api-key-here'

API Key vs Password Authentication

flowchart TB
    Request["HTTP Request to Dashboard"]
    
    CheckAuth{"Authentication<br/>Method?"}
    
    CheckCookie{"Session Cookie<br/>Present?"}
    CheckAPIKey{"X-API-Key Header<br/>or Query Param?"}
    
    ValidateCookie["Validate Session<br/>Against Session Store"]
    ValidateAPIKey["Validate API Key<br/>SHA256(key) == stored_hash"]
    
    Allow["Allow Access<br/>Proceed to Handler"]
    Deny["401 Unauthorized<br/>Redirect to /login"]
    
    Request --> CheckAuth
    
    CheckAuth -->|"Browser Access"| CheckCookie
    CheckAuth -->|"API Access"| CheckAPIKey
    
    CheckCookie -->|"Valid"| ValidateCookie
    CheckCookie -->|"Missing/Invalid"| Deny
    
    CheckAPIKey -->|"Present"| ValidateAPIKey
    CheckAPIKey -->|"Missing"| Deny
    
    ValidateCookie -->|"Session Valid"| Allow
    ValidateCookie -->|"Session Expired"| Deny
    
    ValidateAPIKey -->|"Key Valid"| Allow
    ValidateAPIKey -->|"Key Invalid"| Deny

Sources: README.md:135, docs/V3_COMPLETE_GUIDE.md:313-315


Authentication Storage and Lifecycle

Database Schema

Authentication credentials are stored in the SQLite database scans.db located in ~/.wshawk/. The relevant tables include:

| Table | Columns | Purpose | |-------|---------|---------| | auth_config | password_hash, salt, created_at, updated_at | Stores hashed password and salt | | api_keys | key_hash, name, created_at, last_used | Stores hashed API keys and metadata | | sessions | session_id, user_id, created_at, expires_at | Manages active web sessions |

Session Management

Browser sessions are managed with the following properties:

  • Session Lifetime: 24 hours by default
  • Storage: In-memory session store backed by SQLite for persistence
  • Cookie Attributes: HttpOnly, Secure (when using TLS), SameSite=Strict
  • Session Expiry: Automatic cleanup of expired sessions on dashboard startup

Security Implementation Diagram

graph TB
    subgraph "Environment Variables"
        EnvPass["WSHAWK_WEB_PASSWORD<br/>(Plaintext)"]
        EnvAPIKey["WSHAWK_API_KEY<br/>(Plaintext)"]
    end
    
    subgraph "Dashboard Initialization"
        Init["wshawk --web Startup"]
        HashPass["SHA256 Password<br/>+ Generate Salt"]
        HashAPI["SHA256 API Key"]
    end
    
    subgraph "Persistent Storage"
        DB["~/.wshawk/scans.db"]
        AuthTable["auth_config Table<br/>(password_hash, salt)"]
        KeyTable["api_keys Table<br/>(key_hash)"]
    end
    
    subgraph "Runtime Authentication"
        WebReq["Browser Request<br/>/login"]
        APIReq["API Request<br/>/api/scans"]
        SessionStore["In-Memory Session Store"]
        Validator["Authentication Validator"]
    end
    
    EnvPass --> Init
    EnvAPIKey --> Init
    
    Init --> HashPass
    Init --> HashAPI
    
    HashPass --> AuthTable
    HashAPI --> KeyTable
    
    AuthTable --> DB
    KeyTable --> DB
    
    WebReq --> Validator
    APIReq --> Validator
    
    Validator --> DB
    Validator --> SessionStore
    
    DB -.->|"Read Hashes"| Validator
    SessionStore -.->|"Check Session"| Validator

Sources: RELEASE_3.0.0.md:16-19, docs/V3_COMPLETE_GUIDE.md:294-302


Security Considerations

Password Storage Best Practices

The authentication system implements several security measures:

  1. No Plaintext Storage: Passwords and API keys are never stored in plaintext
  2. Salted Hashing: Each password uses a unique salt to prevent rainbow table attacks
  3. SHA-256 Algorithm: Industry-standard hashing algorithm
  4. No Logging: Authentication credentials are never written to log files

Deployment Security

For production deployments, additional security layers are recommended:

# Example nginx reverse proxy configuration
location / {
    proxy_pass http://127.0.0.1:5000;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    
    # Force HTTPS
    if ($scheme != "https") {
        return 301 https://$host$request_uri;
    }
}

Security Recommendations:

| Risk | Mitigation | |------|------------| | Plaintext transmission | Deploy behind TLS-enabled reverse proxy (nginx, Apache) | | Weak passwords | Enforce strong password policy (min 12 characters, complexity) | | API key exposure | Rotate API keys regularly, use separate keys per integration | | Session hijacking | Enable Secure and HttpOnly cookie attributes via HTTPS | | Brute force attacks | Implement rate limiting on /login endpoint |

Sources: docs/V3_COMPLETE_GUIDE.md:299-302


Configuration Examples

Example 1: Local Development (No Authentication)

# Start dashboard without authentication (localhost only)
wshawk --web --host 127.0.0.1 --port 5000

In this mode, the dashboard is accessible without credentials. Only use this for local testing.

Example 2: Password-Protected Dashboard

# Set strong password
export WSHAWK_WEB_PASSWORD='MyS3cur3P@ssw0rd!'

# Launch dashboard
wshawk --web --host 0.0.0.0 --port 5000

Access the dashboard at http://your-server:5000, then log in with the configured password.

Example 3: API Key for CI/CD Integration

# Generate and set API key
export WSHAWK_API_KEY='wshawk-api-$(openssl rand -hex 32)'

# Launch dashboard
wshawk --web --api-key "$WSHAWK_API_KEY"

# Use in CI/CD pipeline
curl -X POST http://dashboard:5000/api/scans \
  -H "X-API-Key: $WSHAWK_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"target": "ws://test.example.com", "options": {"smart_payloads": true}}'

Example 4: Docker with Environment File

# .env file
WSHAWK_WEB_PASSWORD=production_password_here
WSHAWK_API_KEY=production_api_key_here

# docker-compose.yml
version: '3.8'
services:
  wshawk:
    image: rothackers/wshawk:latest
    env_file: .env
    command: wshawk --web --host 0.0.0.0
    ports:
      - "5000:5000"
    volumes:
      - ./wshawk_data:/root/.wshawk

Sources: README.md:117-127


Hierarchical Configuration Integration

The authentication system integrates with the wshawk.yaml hierarchical configuration system. Credentials can be resolved from environment variables using the env: prefix:

# wshawk.yaml
web:
  authentication:
    password: "env:WSHAWK_WEB_PASSWORD"  # Resolved from environment
    api_key: "env:WSHAWK_API_KEY"
  
  session:
    lifetime_hours: 24
    cookie_secure: true  # Requires HTTPS
    cookie_httponly: true

This approach allows secret management without hardcoding credentials in configuration files. For more information on the configuration system, see Configuration System.

Sources: README.md:137-150


Authentication State Machine

stateDiagram-v2
    [*] --> Unauthenticated
    
    Unauthenticated --> Authenticating: "POST /login with password"
    Unauthenticated --> Authenticating: "API request with X-API-Key"
    
    Authenticating --> Authenticated: "Credentials Valid"
    Authenticating --> Unauthenticated: "Credentials Invalid<br/>(401 Response)"
    
    Authenticated --> SessionActive: "Browser Session Created"
    Authenticated --> APIKeyActive: "API Key Validated"
    
    SessionActive --> SessionActive: "Valid Session Cookie<br/>on Each Request"
    SessionActive --> Unauthenticated: "Session Expired (24h)"
    SessionActive --> Unauthenticated: "User Logout"
    
    APIKeyActive --> APIKeyActive: "Valid X-API-Key Header<br/>on Each Request"
    APIKeyActive --> Unauthenticated: "Invalid API Key"
    APIKeyActive --> Unauthenticated: "API Key Revoked"

Sources: docs/V3_COMPLETE_GUIDE.md:313-315


Programmatic Access Example

# Example: Python script using API key authentication
import requests
import os

# Read API key from environment
API_KEY = os.environ['WSHAWK_API_KEY']
BASE_URL = 'http://localhost:5000'

# Headers with API key
headers = {
    'X-API-Key': API_KEY,
    'Content-Type': 'application/json'
}

# Start a new scan
response = requests.post(
    f'{BASE_URL}/api/scans',
    headers=headers,
    json={
        'target': 'ws://example.com/api',
        'options': {
            'smart_payloads': True,
            'playwright': False
        }
    }
)

scan_id = response.json()['scan_id']
print(f"Scan started: {scan_id}")

# Poll scan status
status_response = requests.get(
    f'{BASE_URL}/api/scans/{scan_id}',
    headers=headers
)

print(f"Status: {status_response.json()['status']}")

For complete REST API documentation, see REST API Reference.

Sources: README.md:135, docs/V3_COMPLETE_GUIDE.md:317-330


Troubleshooting

Common Authentication Issues

| Issue | Symptoms | Solution | |-------|----------|----------| | Password not set | Dashboard accessible without login | Set WSHAWK_WEB_PASSWORD environment variable | | Wrong password | "401 Unauthorized" on login | Verify WSHAWK_WEB_PASSWORD value | | Session expired | Redirected to login unexpectedly | Sessions expire after 24 hours; re-login required | | API key rejected | "401 Unauthorized" on API calls | Verify X-API-Key header matches WSHAWK_API_KEY | | CORS errors | Browser blocks API calls | Deploy behind reverse proxy with proper CORS headers |

Verifying Authentication Configuration

# Check if password is set
echo $WSHAWK_WEB_PASSWORD

# Check if API key is set
echo $WSHAWK_API_KEY

# Test API key authentication
curl -v -H "X-API-Key: $WSHAWK_API_KEY" \
  http://localhost:5000/api/scans

# Expected: 200 OK response with scan list
# If 401: API key is invalid or not configured

Sources: docs/V3_COMPLETE_GUIDE.md:413-420