Implement signed API communication to improve security
build / build-linux-amd64 (push) Successful in 1m50s
build / build-linux-amd64 (push) Successful in 1m50s
This commit is contained in:
+80
-1
@@ -303,6 +303,85 @@ keys and what each one does.
|
||||
|
||||
---
|
||||
|
||||
## Agent API signing (per-peer)
|
||||
|
||||
`POST /api/heartbeat`, `POST /api/sysinfo`, and
|
||||
`POST /api/unattended-password` are the three agent-facing endpoints
|
||||
that write per-device state. Stock RustDesk and managed builds
|
||||
(hello-agent) both call the first two; only managed builds use the
|
||||
third. Each peer row has a `managed` flag that gates whether the
|
||||
server requires a per-request Ed25519 signature on these endpoints;
|
||||
everything else (`/api/peers`, `/api/ab/*`, audit, recordings, OIDC,
|
||||
etc.) is unaffected. See [AGENT-API-AUTH.md](AGENT-API-AUTH.md) for
|
||||
the full out-of-scope list.
|
||||
|
||||
| `peer.managed` | Heartbeat / sysinfo behaviour |
|
||||
|----------------|----------------------------------------------------------------------------------------|
|
||||
| `0` (default) | Unsigned posts accepted (stock-client compatible). Signed posts still verified. |
|
||||
| `1` | Signature required; unsigned posts return 401. First valid sig auto-promoted to here. |
|
||||
|
||||
Default is `0` after the migration, so **stock RustDesk clients are not
|
||||
affected by the rollout** — they keep posting unsigned, the server keeps
|
||||
accepting. The first valid signature the server sees from a peer is the
|
||||
TOFU promote: that peer's `managed` flips to `1` for good, and unsigned
|
||||
requests claiming that `id` are rejected from then on.
|
||||
|
||||
The wire format and verification details live in
|
||||
[AGENT-API-AUTH.md](AGENT-API-AUTH.md). What you need to know to operate:
|
||||
|
||||
### Dashboard
|
||||
|
||||
The Devices page has a per-row **Auth** column:
|
||||
|
||||
- *Signed* (emerald badge) — `peer.managed = 1`. The peer's heartbeat
|
||||
and sysinfo posts must carry a valid signature; spoofed unsigned
|
||||
requests are rejected.
|
||||
- *Unsigned* (slate badge) — `peer.managed = 0`. Legacy path. Anyone
|
||||
who knows the id+uuid can post inventory and heartbeats as this
|
||||
device.
|
||||
|
||||
The row's action menu has two new entries (mutually exclusive based on
|
||||
current state):
|
||||
|
||||
- **Require signed API** — flips `managed` to 1 (no confirm — it
|
||||
strengthens security). Useful for pre-enrolling a peer record
|
||||
before the agent has booted, or for force-locking a peer if you
|
||||
want to fail fast when an agent is not signing yet.
|
||||
- **Allow unsigned API** — flips `managed` to 0 (confirm dialog,
|
||||
because this reopens the spoofing surface). Use when a managed
|
||||
agent has been uninstalled and replaced with stock RustDesk on the
|
||||
same hardware.
|
||||
|
||||
### API
|
||||
|
||||
`PUT /api/peers/:id/managed` with body `{"managed": true|false}`, gated
|
||||
on the `is_admin` flag of the calling session, returns
|
||||
`{"ok":true,"managed":<bool>}`. Same effect as the dashboard toggle —
|
||||
the dashboard handler just calls this internally after reading the
|
||||
current value to avoid stale-toggle races.
|
||||
|
||||
### Operational notes
|
||||
|
||||
- **Mixed fleets are fine.** Stock and hello-agent clients can target
|
||||
the same hbbs. The gate is per-peer, not per-deployment.
|
||||
- **Replacing hello-agent with stock RustDesk on a device.** The
|
||||
device's `peer.managed` is stuck at 1; the stock client doesn't
|
||||
sign and will start getting 401s. Either re-deploy a signing build
|
||||
*or* flip the peer back to Unsigned in the dashboard.
|
||||
- **TLS still recommended.** Signing protects against id+uuid spoof,
|
||||
not against the unsigned-by-default endpoint surface elsewhere
|
||||
(`/api/login`, `/api/record`, dashboard) — those still rely on
|
||||
whatever TLS termination is in front of hbbs. See *TLS deployment*
|
||||
earlier in this doc.
|
||||
- **Clock skew tolerance is ±5 minutes.** If a host's clock drifts
|
||||
past that, heartbeat starts failing 401. Keep NTP healthy on
|
||||
managed peers; the server's clock is the canonical one.
|
||||
- **The replay cache lives in-memory only.** A hbbs restart clears
|
||||
it. The 5-minute timestamp window bounds the worst-case replay
|
||||
exposure across restarts.
|
||||
|
||||
---
|
||||
|
||||
## Address books
|
||||
|
||||
- **Personal books** are owned per-user and managed from the user's desktop client. The dashboard surfaces them read-only.
|
||||
@@ -326,7 +405,7 @@ If you set `--ab-legacy-mode=on`, `/api/ab/personal` 404s and clients fall back
|
||||
| `/admin/oidc/providers` | none | JSON list of enabled providers, used by login.html |
|
||||
| `/admin/login/oidc/:name` | none | Starts admin OIDC flow (302s to IdP) |
|
||||
| `/admin/pages/users` | cookie + admin | Users page fragment (incl. inline edit-profile / password-reset / TOTP-disable per row) |
|
||||
| `/admin/pages/devices` | cookie + admin | Devices (incl. delete) |
|
||||
| `/admin/pages/devices` | cookie + admin | Devices (incl. delete, force-disconnect, force-sysinfo, toggle managed-auth — see [AGENT-API-AUTH.md](AGENT-API-AUTH.md)) |
|
||||
| `/admin/pages/groups` | cookie + admin | Device groups |
|
||||
| `/admin/pages/strategies` | cookie + admin | Strategy management |
|
||||
| `/admin/pages/address-books` | cookie + admin | Personal + shared books |
|
||||
|
||||
Reference in New Issue
Block a user