Malachi.Dashboard.SecurityHeaders (malachi v0.8.13)

View Source

Security headers for dashboard HTTP responses.

Implements defense-in-depth security controls:

  • Content Security Policy (CSP)
  • HTTP Strict Transport Security (HSTS)
  • X-Frame-Options (clickjacking prevention)
  • X-Content-Type-Options (MIME sniffing prevention)
  • X-XSS-Protection
  • Referrer-Policy
  • CORS (Cross-Origin Resource Sharing)

Summary

Functions

Adds security headers to an HTTP response string.

Builds CORS headers for API endpoints.

Builds Content Security Policy header.

Builds HTTP Strict Transport Security header.

Prepends headers to an HTTP response string.

Functions

add_security_headers(response, request_path, request_origin \\ nil)

Adds security headers to an HTTP response string.

Parameters

  • response - HTTP response string (must include status line and headers)
  • request_path - Path being accessed (e.g., "/", "/metrics", "/stream")

Returns

Modified response string with security headers prepended.

Examples

iex> response = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\n<html>..."
iex> SecurityHeaders.add_security_headers(response, "/")
"HTTP/1.1 200 OK\r\nX-Frame-Options: DENY\r\nContent-Type: text/html\r\n\r\n<html>..."

build_cors_headers(request_path, request_origin \\ nil)

Builds CORS headers for API endpoints.

CORS is only enabled for /metrics and /stream endpoints when explicitly configured. With the default wildcard whitelist every origin gets *; with an explicit whitelist the request's own Origin is echoed back, and only when it is listed, since Access-Control-Allow-Origin accepts a single origin. An origin outside the whitelist (or a request with no Origin) gets no allow header, which the browser reads as not allowed, but still gets Vary: origin so a cache cannot reuse that denial for a whitelisted origin.

Returns a list of {name, value} tuples, empty when CORS does not apply at all. Malachi.Dashboard uses it for both the real responses and the OPTIONS preflight, so a preflight can never advertise a permission the actual request would not receive.

Configuration

export MALACHI_DASHBOARD_CORS_ENABLED=true
export MALACHI_DASHBOARD_CORS_ORIGINS="https://app.example.com,https://admin.example.com"

build_csp_header()

Builds Content Security Policy header.

Default policy allows 'unsafe-inline' for compatibility with current dashboard. Can be customized via MALACHI_DASHBOARD_CSP environment variable.

Future Hardening

For production environments, consider removing 'unsafe-inline' and using nonces:

export MALACHI_DASHBOARD_CSP="default-src 'self'; script-src 'self' 'nonce-RANDOM'; style-src 'self' 'nonce-RANDOM'"

This requires refactoring dashboard HTML to use nonce attributes.

build_hsts_header()

Builds HTTP Strict Transport Security header.

Only included when TLS is enabled. Instructs browsers to only connect via HTTPS for the specified duration (default: 1 year).

prepend_headers(response, headers)

Prepends headers to an HTTP response string.

Inserts headers after the status line, before existing headers.

Examples

iex> response = "HTTP/1.1 200 OK\r\nContent-Type: text/html\r\n\r\nBody"
iex> headers = [{"x-frame-options", "DENY"}]
iex> prepend_headers(response, headers)
"HTTP/1.1 200 OK\r\nX-Frame-Options: DENY\r\nContent-Type: text/html\r\n\r\nBody"