fix(web): refuse cross-site state-changing requests (Origin/Referer check) (#674)

The web interface refuses state-changing requests (POST/PUT/PATCH/DELETE)
whose Origin (or, without one, Referer) is not the host they were sent to,
or is null: 403 CROSS_SITE_REQUEST (web_interface/origin_guard.py). Any
website a LAN user visited could otherwise make their browser POST a plain
form to the Pi. /api/v3/system/action also refuses form-encoded and
text/plain bodies (415) unless sent by HTMX. Clients that send no Origin or
Referer (curl, requests, Home Assistant, the MQTT bridge) are unaffected.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Chuck
2026-09-30 09:02:01 -04:00
committed by GitHub
co-authored by Claude Opus 5.5
parent c3a7a110c4
commit ba38a83c2c
8 changed files with 565 additions and 10 deletions
+10
View File
@@ -412,6 +412,16 @@ The API blueprint (`web_interface/blueprints/api_v3/`) is registered at
- No authentication is currently implemented
- Recommended for trusted networks only
**Other websites:**
- A web page you open elsewhere could otherwise make your browser send
commands to the Pi (reboot, update, config changes). The interface refuses
any change request whose `Origin`/`Referer` header names a different site
(403 `CROSS_SITE_REQUEST`), so use the interface from its own address.
- Scripts, curl, Home Assistant and the MQTT bridge send no such header and
keep working. Behind a reverse proxy, forward the original `Host` header
with its port (nginx: `proxy_set_header Host $http_host;` -- `$host`
drops the port).
**Best Practices:**
1. Run on a private network (not exposed to internet)
2. Use a firewall to restrict access if needed