security: harden web server, daemon socket, and write paths
Security review findings, fixed and verified: Critical - Fix unauthenticated arbitrary file read: the SPA catch-all route joined the raw URL path onto the dist dir without containment, so encoded '..' segments (/%2e%2e/etc/passwd) leaked any file readable by the root server. Resolve with realpath and reject paths outside the dist dir (fail-closed 404). High - Daemon socket: serve_start no longer accepts caller-chosen host/port. The socket is world-connectable (unprivileged CLI users), so callers could previously rebind the root web server to 0.0.0.0. The daemon now always binds the operator-configured address and reports it in the response; the CLI warns on mismatch. Medium - Remove the per-request max_delta_khz override from the API: the server-enforced safety cap is now authoritative. CLI direct paths (write, profile apply, verify) honor the configured cap; --max-delta still overrides for explicit root use. - Snapshot restore: confine filepath to the snapshot directory (realpath containment; blocks symlink escapes). - Login lockout: honor X-Forwarded-For only for peers listed in the new trusted_proxies config (rightmost untrusted hop), so the per-IP lockout works behind a reverse proxy. Spoofed headers from untrusted peers are ignored. - /api/shutdown: new allow_api_shutdown config (default true); shared systems can disable the API shutdown path. TLS (opt-in, like auth) - New ssl_certfile/ssl_keyfile config + CLI flags (serve start, service install/configure, --no-ssl to disable). When active: HTTPS for UI/API, wss:// for WebSockets, Secure session cookie, CLI auto-switches to https://. Cert/key paths are validated up front with a clear error instead of a silent uvicorn crash. Tests & docs - tests/test_security.py: standalone regression tests (no new deps) covering SPA containment, snapshot containment, cap removal, client-IP derivation, proxy normalization, TLS scheme detection, and daemon host/port hardening. - README + Usage-Guide: TLS section, new config keys, updated security notes.
This commit is contained in:
1 parent
8956fc9d7b
commit
39701c12ff
9 files changed
+648
-55
No files matched your search
+23
-1
@@ -145,6 +145,27 @@ Adding the first user **switches the server into authenticated mode immediately*
|
||||
- The user store file should stay root-owned and `0600` (the CLI enforces this).
|
||||
- The web UI and API are still only as safe as the network path to the server — bind to a trusted interface (`--host`) and/or firewall the port. Authentication protects against casual access, not a determined network attacker.
|
||||
- The `nvcurve user` commands and the user store require root; day-to-day sign-in does not.
|
||||
- The login lockout is keyed by client IP. Behind a reverse proxy all clients share the proxy's IP — set `trusted_proxies` in `/etc/nvcurve/config.json` (e.g. `["127.0.0.1"]`) so the lockout uses the real client IP from `X-Forwarded-For`. The header is only honoured for peers you list there (it is spoofable otherwise).
|
||||
- On shared systems consider setting `allow_api_shutdown: false` so users cannot stop the server via the API (manage it with systemd instead).
|
||||
- The frequency safety cap (`max_delta_khz`) is enforced by the server from its config; API clients cannot raise it per request. The CLI's `--max-delta` (root-only, direct hardware path) can still override it for a single write.
|
||||
|
||||
## TLS (HTTPS)
|
||||
|
||||
The server speaks **plain HTTP by default**. When you expose it beyond localhost, enable TLS so credentials and session cookies are not sent in cleartext:
|
||||
|
||||
```bash
|
||||
# Persistent (stored in /etc/nvcurve/config.json, used by the daemon too)
|
||||
sudo nvcurve service configure --ssl-certfile /path/to/cert.pem --ssl-keyfile /path/to/key.pem
|
||||
|
||||
# One-off
|
||||
nvcurve serve start --ssl-certfile /path/to/cert.pem --ssl-keyfile /path/to/key.pem
|
||||
```
|
||||
|
||||
- Both files must be set for TLS to activate; the UI then lives at `https://<host>:8042` and the WebSocket upgrades to `wss://` automatically.
|
||||
- To disable TLS again: `sudo nvcurve service configure --no-ssl` (removes the certificate/key from the config).
|
||||
- The session cookie gets the `Secure` flag, so it is only sent over HTTPS.
|
||||
- A self-signed certificate is fine for a home LAN (the browser shows a warning); for multi-user setups use a certificate your browser trusts.
|
||||
- The CLI detects TLS from the config/runtime info and switches to `https://` automatically.
|
||||
|
||||
## CLI Reference
|
||||
|
||||
@@ -251,13 +272,14 @@ nvcurve service uninstall
|
||||
sudo nvcurve service configure --auto-serve
|
||||
sudo nvcurve service configure --no-auto-serve
|
||||
sudo nvcurve service configure --host 0.0.0.0 --port 8042
|
||||
sudo nvcurve service configure --ssl-certfile /path/to/cert.pem --ssl-keyfile /path/to/key.pem
|
||||
```
|
||||
|
||||
## Configuration Files
|
||||
|
||||
| File | Purpose |
|
||||
| --- | --- |
|
||||
| `/etc/nvcurve/config.json` | Persistent config (host, port, auto-serve, default profiles) |
|
||||
| `/etc/nvcurve/config.json` | Persistent config (host, port, auto-serve, TLS, safety cap, default profiles) |
|
||||
| `/etc/nvcurve/profiles/*.json` | Saved profiles |
|
||||
| `/var/cache/nvcurve/snapshots/` | Auto-saved snapshots before writes |
|
||||
| `/run/nvcurve.json` | Runtime server info (host, port, PID) |
|
||||
|
||||
Reference in new issue
Block a user