Add the HTTP hardening the policy requires before 1.0 (closes #108) #132

Merged
clawbot merged 1 commits from issue-108-http-hardening into next 2026-10-20 01:36:19 +02:00
Collaborator

Closes #108.

  • SecurityHeadersMiddleware sets the six headers REPO_POLICIES.md lists on every answer. The Content-Security-Policy is default-src 'self', and it allows scripts and styles only with a nonce made for each answer. The five page templates put that nonce on their <style> and <script> tags. A nonce cannot cover a style attribute, so the four inline ones became CSS rules. README explains how inline content is handled.
  • RealIPMiddleware replaces chi's RealIP. A request from a proxy listed in TRUSTED_PROXIES (addresses and CIDR ranges; an invalid value stops the start) gets the last X-Forwarded-For entry that is not a trusted proxy. Every other request keeps its TCP peer.
  • The JSON routes and the health check send fixed messages for anything but database.ErrNoRoute and database.ErrInvalidIP, and log the detail. That includes the 400 for a prefix that does not parse, which used to send the parser's text.

Not visible in the diff: behind a proxy, the request log and /ip/ show the proxy's address until TRUSTED_PROXIES is set (README "Running under upaas").

  • Judgement call: X-Real-IP and True-Client-IP are no longer read. Most proxies pass a client's True-Client-IP through unchanged, and chi read it first.
  • Deviation: the templates change even though the brief's file list leaves them out; the nonce has to be written on each block.
  • Unverified: the fixed message for a host name that does not resolve has no test, since a test would need DNS.
  • Unchanged: when the store fails for every address of an IP lookup, the answer is still 404.

Model: opus-5-5

Closes https://git.eeqj.de/sneak/routewatch/issues/108. - `SecurityHeadersMiddleware` sets the six headers REPO_POLICIES.md lists on every answer. The Content-Security-Policy is `default-src 'self'`, and it allows scripts and styles only with a nonce made for each answer. The five page templates put that nonce on their `<style>` and `<script>` tags. A nonce cannot cover a `style` attribute, so the four inline ones became CSS rules. README explains how inline content is handled. - `RealIPMiddleware` replaces chi's `RealIP`. A request from a proxy listed in `TRUSTED_PROXIES` (addresses and CIDR ranges; an invalid value stops the start) gets the last `X-Forwarded-For` entry that is not a trusted proxy. Every other request keeps its TCP peer. - The JSON routes and the health check send fixed messages for anything but `database.ErrNoRoute` and `database.ErrInvalidIP`, and log the detail. That includes the 400 for a prefix that does not parse, which used to send the parser's text. Not visible in the diff: behind a proxy, the request log and `/ip/` show the proxy's address until `TRUSTED_PROXIES` is set (README "Running under upaas"). - Judgement call: `X-Real-IP` and `True-Client-IP` are no longer read. Most proxies pass a client's `True-Client-IP` through unchanged, and chi read it first. - Deviation: the templates change even though the brief's file list leaves them out; the nonce has to be written on each block. - Unverified: the fixed message for a host name that does not resolve has no test, since a test would need DNS. - Unchanged: when the store fails for every address of an IP lookup, the answer is still 404. Model: opus-5-5
clawbot added the needs-review label 2026-10-20 01:25:20 +02:00
clawbot self-assigned this 2026-10-20 01:25:20 +02:00
clawbot added 1 commit 2026-10-20 01:25:20 +02:00
Every answer carries the six security headers REPO_POLICIES.md lists.
The Content-Security-Policy allows inline content only with a nonce made
for that answer; the pages put it on their style and script blocks and
drop their four style attributes.

The request log and /ip/ take a forwarded address only from a proxy
listed in TRUSTED_PROXIES, which stops the start when set but invalid:
the last X-Forwarded-For entry that is not a trusted proxy. X-Real-IP
and True-Client-IP are no longer read.

The JSON routes and the health check send fixed messages in place of
database, parser and resolver errors, and log the detail.

Model: opus-5-5
Author
Collaborator

Review passed.

Model: opus-5-5

Review passed. Model: opus-5-5
clawbot merged commit 89bdda18a5 into next 2026-10-20 01:36:19 +02:00
clawbot deleted branch issue-108-http-hardening 2026-10-20 01:36:19 +02:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: sneak/routewatch#132