Skip to content

Trust the proxy's last X-Forwarded-For hop, and decide trust once - #45

Merged
bricke merged 1 commit into
mainfrom
fix/proxy-headers
Oct 9, 2026
Merged

bricke merged 1 commit into
mainfrom
fix/proxy-headers

Conversation

@bricke

@bricke bricke commented Oct 9, 2026

Copy link
Copy Markdown
Owner

Fixes #29 and #37.

Audit address (#29). Behind the trusted proxy, the audit log recorded the first X-Forwarded-For value. Proxies append the address they saw to whatever the client sent, so the first value was the client's to choose. Logins and admin actions could be logged under a made-up address. The last value, the one the proxy appended, is used now. X-Forwarded-Host and -Proto keep their first value, which the proxy sets. docs/install.md notes which value is used and the nginx line that appends it.

Proxy trust once per request (#37). Whether to believe a request's X-Forwarded-* headers was worked out again (secret compare and address scan) on each of the 3–4 calls a request makes (isHTTPS, clientIP, forwardedHost, isSiteHost).

  • A withForwarded middleware now decides it once and keeps the host, scheme and client address in the request context.
  • Code called outside the middleware, as in the unit tests, still works it out on demand.
  • ProxyIdentity keeps its own check: the gateway uses a stricter rule (secret only) than the UI.

HTTPS state in memory (#37). Port 8080 read the https setting from SQLite on every request, on the single connection the ledger also writes through. It is now read once and kept in memory, and setHTTPSState saves changes to both the database and memory. Only the name and confirm handlers and SeedHTTPSName change it.

Tests:

  • TestForwardedHeadersTrustedLikeIdentity now sends a made-up first hop and expects the proxy's address. It fails on the old first-value code.
  • TestHTTPSStateIsReadOnceAndSaved is new.

Behind the trusted proxy, the audit log recorded the first
X-Forwarded-For value. Proxies append the address they saw to whatever
the client sent, so the first value was the client's to choose, and
logins and admin actions could be logged under a made-up address. The
last value, the one the proxy added, is used now.

Whether to believe a request's X-Forwarded-* headers was worked out
again (shared secret compare, address scan) on each of the 3-4 calls a
request makes. A middleware now decides it once and keeps the host,
scheme and client address in the request context.

Port 8080 also read the HTTPS state from SQLite on every request, on
the single connection the ledger writes through. The state is now read
once and kept in memory; only the HTTPS settings handlers change it.

Fixes #29
Fixes #37
@bricke
bricke merged commit f1be67c into main Oct 9, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Audit log records the client-supplied X-Forwarded-For address

1 participant