mirror of
https://github.com/ChuckBuilds/LEDMatrix.git
synced 2026-10-06 23:35:08 +00:00
fix(web): refuse cross-site state-changing requests (Origin/Referer check)
The web interface had no CSRF protection, on the reasoning that anyone who can forge a request on the LAN can also send it directly. That misses the browser as a confused deputy: any website a LAN user opens can make their browser POST a plain HTML form to http://<pi>:5000. CORS does not stop that request, only hides its answer, and /api/v3/system/action accepted form bodies, so a hostile page could reboot or power off the Pi, pull code, or reach any other mutating route. - web_interface/origin_guard.py: an app-wide before_request hook refuses POST/PUT/PATCH/DELETE whose Origin (or, without one, Referer) is not the host the request was addressed to, and Origin "null", with 403 CROSS_SITE_REQUEST. Requests with neither header (curl, Home Assistant, the MQTT bridge) are not from a browser and pass. Host and port are compared, not the scheme, so a TLS proxy that passes Host through works; X-Forwarded-Host is not trusted (no ProxyFix). - /api/v3/system/action refuses a non-JSON body (415) unless HX-Request is set; every caller in the interface already sends JSON. - app.py comment states the real threat model; SECURITY.md, REST_API_REFERENCE.md, WEB_INTERFACE_GUIDE.md and CHANGELOG updated. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -63,6 +63,14 @@ are intentional rather than vulnerabilities:
|
||||
|
||||
- **No web UI authentication.** The web interface assumes the network
|
||||
it's running on is trusted. Don't expose port 5000 to the internet.
|
||||
"Trusted network" does not mean "trusted websites", though: any page
|
||||
a LAN user opens could make their browser POST to the Pi. So the
|
||||
interface refuses a `POST`/`PUT`/`PATCH`/`DELETE` whose `Origin` (or
|
||||
`Referer`) header names another site (`web_interface/origin_guard.py`),
|
||||
and `/api/v3/system/action` only accepts JSON or HTMX requests. Tools
|
||||
that send neither header (curl, Home Assistant, the MQTT bridge) are
|
||||
unaffected. Not covered: DNS rebinding, and anyone who can reach the
|
||||
port directly.
|
||||
- **Plugins run unsandboxed.** Installed plugins execute in the same
|
||||
Python process as the display loop with full file-system and
|
||||
network access. Review plugin code (especially third-party plugins
|
||||
|
||||
Reference in New Issue
Block a user