Middleware & Security

Host Validation & Cache-Control

Host Validation (Allowed Hosts)

How it works

  • Compares the request Host header against the list of allowed hosts
  • Blocks requests with a non-allowed host (HTTP 400)
  • Protects against Host Header Injection attacks

HTTP/2 and the Host header

HTTP/2 does not send a Host header — it uses the :authority pseudo-header instead. Runique handles this automatically: if the Host header is absent, the middleware reads the authority from request.uri().authority().

This covers direct HTTP/1.1, HTTP/2 (e.g. ACME or Cloudflare), and reverse proxies that proxy over HTTP/2.

Logging

Rejections can be logged via RuniqueLog:

.with_log(|l| l.host_validation(Level::WARN))

In production, WARN is recommended to detect attacks or misconfigurations.

Configuration via the builder

Host validation is configured in main.rs via the builder — there is no environment variable for this:

.middleware(|m| {
    m.with_allowed_hosts(|h| {
        h.enabled(!is_debug())
         .host("example.com")
         .host(".example.com")  // matches example.com AND all its subdomains
    })
})

Supported patterns

  • "localhost" — exact match
  • ".example.com" — matches example.com and *.example.com
  • "*" — all hosts (⚠️ dangerous in production)

Debug mode

In DEBUG=true, typically use .enabled(!is_debug()) to disable validation during development.


Cache-Control

Development mode (DEBUG=true)

no-cache headers are added to force reloads:

Cache-Control: no-cache, no-store, must-revalidate
Pragma: no-cache

Production mode (DEBUG=false)

Caching headers are enabled for performance.