mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-10-04 06:15:09 +00:00
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:
@@ -18,6 +18,17 @@ top level instead of under `data` (install-from-url, registry-from-url, the
|
||||
auth endpoints, upload endpoints, `system/git-info`, `system/check-update`),
|
||||
the entry below says so.
|
||||
|
||||
**Cross-site requests are refused.** A `POST`, `PUT`, `PATCH` or `DELETE`
|
||||
carrying an `Origin` header (or, without one, a `Referer`) that is not the
|
||||
host the request was sent to gets `403` with `"error_code":
|
||||
"CROSS_SITE_REQUEST"`; so does `Origin: null`. This stops other websites from
|
||||
driving the Pi through a LAN user's browser. Scripts, curl, Home Assistant and
|
||||
the MQTT bridge send neither header and are unaffected. A browser page on
|
||||
another origin (a dashboard you host elsewhere, say) can no longer call the
|
||||
API; call it server-side instead. Behind a reverse proxy, pass the original
|
||||
`Host` through, port included (nginx: `proxy_set_header Host $http_host;`;
|
||||
`$host` drops the port) -- `X-Forwarded-Host` is not read.
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Configuration](#configuration)
|
||||
@@ -1388,7 +1399,10 @@ Fetches `origin` and lists branches to switch to: `current`, `upstream`,
|
||||
|
||||
**POST** `/api/v3/system/action`
|
||||
|
||||
Execute system-level actions. JSON or form data.
|
||||
Execute system-level actions. Send JSON (`Content-Type: application/json`).
|
||||
A form-encoded or `text/plain` body is accepted only with an `HX-Request`
|
||||
header (HTMX sends it; a cross-site HTML form cannot) and is otherwise
|
||||
refused with `415`.
|
||||
|
||||
**Request Body**:
|
||||
```json
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user