New permitted_hosts proxy config (enabled by Sinatra 4)

Sinatra 4 and permitted_hosts config

Smart Proxy got support for Sinatra 4

Sinatra is a lightweight Ruby web framework used to build and run the Foreman Proxy.

PR #955 made it possible for Smart Proxy to use Sinatra 4 (and the required Rack 3).

It’s still possible to use Sinatra 2 (and the required Rack 2). When we migrate core Foreman to Sinatra 4, it will become the only supported option in Smart Proxy as well.

Sinatra 4 allows host authorization

Sinatra 4 adds an option to set :permitted_hosts. It is a list of hosts that the proxy “identifies as.” In other words, when a client makes a request, it needs to use a Host header matching one of the permitted_hosts; otherwise, it is rejected.

A request using the legitimate host is accepted:

curl https://smart-proxy-hostname.example.com/features

A request using a malicious host is rejected:

curl https://10.0.1.42/features --header 'Host: attack.example.com'

Note that this has nothing to do with the request’s origin and is unrelated to :trusted_hosts.

Why?

CVE-2024-21510 allows SSRF (server-side request forgery) by giving a server a fake hostname and making it consider its own.

Attack example: make a client access smart-proxy-hostname.example.com with an X-Forwarded-Host: attack.example.com header (for example, using JavaScript and a DNS rebinding attack). Smart Proxy trusts the header and redirects that request to attack.example.com, making the client actually connect to the attacker and bypass the same-origin policy.

How?

Set :permitted_hosts in Smart Proxy’s settings.yml.

foremanctl PR #900 allows foremanctl to configure Smart Proxy, and you can add more accepted hostnames using the --server-alias parameter.

Smart Proxy PR #960 makes Smart Proxy abide by that value.

An empty :permitted_hosts defaults to all hostnames being accepted. That means it’s backwards compatible. It also means that with an empty or unset :permitted_hosts, you don’t use the additional security Sinatra 4 provides.

Result

$ curl -k https://quadlet.example.com:8443/features
["logs","script"]

$ curl -k https://quadlet.example.com:8443/features -H "X-Forwarded-Host: attack.example.com"
Host not permitted

1 Like