Skip to content

RD-API-Server v1.7.0

Latest

Choose a tag to compare

@TheJakeBraun TheJakeBraun released this 29 Sep 05:07
b812f0c

Before you upgrade — read this

  1. Back up the database and the application key together. This release encrypts more data
    with the application key (address-book peer passwords/hashes and pending OIDC results, in
    addition to the authenticator secrets encrypted since v1.4). The key is APP_KEY if you set
    one, otherwise the key the container generated and persisted at storage/app/.appkey.
    A database restored without its matching key cannot decrypt those values — address-book
    peers would lose their saved passwords, and authenticator (TOTP) secrets would be unreadable.
    Keep the key and the database in the same backup, and give every API replica the same
    APP_KEY (and APP_PREVIOUS_KEYS when rotating).
  2. Migrations run automatically when the container starts (the entrypoint runs
    php artisan migrate --force, as in earlier releases). Five new migrations run once:
    Migration What it does Reversible
    add_presets_applied_at_to_devices_table Records when a device's enrollment-time presets were applied. Devices that have already reported inventory are marked as done. Yes
    add_approval_to_oauth_sessions_table Adds the OIDC approval-step columns. Yes
    hash_client_and_deploy_tokens Replaces every stored client bearer token and deploy token with its SHA-256 digest in place (tokens already issued keep working), keys pending OIDC logins by a digest of the polling code, and encrypts an undelivered OIDC result. No — see below
    encrypt_address_book_peer_secrets Encrypts address_book_peers.password and .hash with the application key. Idempotent. Yes, while the key is available
    add_two_factor_last_counter_to_users_table TOTP replay protection. Yes
  3. Upgrade in a short maintenance window, not as a mixed-version rolling update. Stop old
    replicas, back up, start one upgraded instance (it migrates), then start the rest. An old
    replica still running after the token migration cannot authenticate anyone (the plaintext token
    column no longer exists), and an old replica would write unencrypted peer secrets.
  4. Downgrading after the upgrade signs everyone out. The token digests cannot be turned back
    into tokens, so rolling back to v1.6.x requires every client to sign in again and every deploy
    token to be recreated. Restore the pre-upgrade backup instead if you must go back.
docker compose pull && docker compose up -d

What changed

Device presets can no longer move an enrolled device (High)

/api/sysinfo accepts the OPTION_PRESET_* values a custom client or rustdesk --assign bakes in
(strategy, device group, address book, displayed name/note). Previously they were re-applied on
every upload and overrode admin assignments, so anyone who could read a machine's RustDesk id
and uuid (any local user) could move it into any strategy — and read that strategy's options,
including default-connect-password and proxy credentials — or into any device group, creating
groups at will.

Now presets are an enrollment-time action, which is how they were documented ("devices
auto-file … on first contact"):

  • They apply on the device's first accepted sysinfo upload only.
  • They fill blanks and never overwrite: an existing direct strategy, a non-default device
    group, or an admin-set name/note is kept.
  • strategy_name and device_group_name are matched against existing strategies/groups;
    unknown names are ignored, and a device can never create a device group.
  • The client still receives SYSINFO_UPDATED as before.

Legitimate enrollment is unchanged: a new machine deployed with a custom client or --assign
still lands in its preset strategy and group. Behaviour change to note: if you relied on a
custom client's device_group_name preset creating a group, create that group in the console
first. To re-file a device that is already enrolled, use the console, the v1 API, or
rustdesk --assign (deploy-token authenticated) — not a new sysinfo upload.

Delegated administrators stay inside their scope (Medium-High)

  • A strategy that is also assigned directly to a device outside a delegated admin's scope is
    no longer considered in scope for that admin.
  • rustdesk --assign / /api/devices/cli and /api/devices/deploy with a delegated admin's
    deploy token now respect that admin's scope: only in-scope strategies, only existing in-scope
    device groups (no group creation), and no adoption of a device owned outside the scope. Full
    administrators' tokens behave exactly as before.
  • Strategy options that point a client at other infrastructure or through a credentialed proxy —
    custom-rendezvous-server, relay-server, api-server, key, proxy-url, proxy-username,
    proxy-password — can now be added, changed or removed only by full administrators (console
    and v1 API). Delegated editors can still save strategies that contain them unchanged.

OIDC device sign-in needs an explicit approval (High impact)

Signing in to RustDesk with an OIDC/OAuth provider now shows an approval page after the
provider sign-in: the requesting device's name, OS, RustDesk ID, the IP address that started the
request, and the time. No token is issued until the person presses Approve sign-in on this
device
(a POST bound to a one-time value in the page and a same-site cookie). "Deny" discards the
request. This stops a phishing link built from an attacker's own sign-in request from silently
handing the victim's token to the attacker's device.

The RustDesk client's polling (/api/oidc/auth-query) and every JSON shape are unchanged — the
client simply keeps waiting until the user approves. Also:

  • /api/oidc/auth is rate-limited per source (20 per minute; IPv6 per /64).
  • The runtime Nginx access log no longer records the query strings of /api/oidc/auth-query and
    the OIDC callback, which carry the polling secret. If you run your own proxy in front, consider
    doing the same there: the protocol fixes these values in the query string.

Credentials are no longer stored in plaintext (Medium)

  • Client bearer tokens and deploy tokens are stored as SHA-256 digests and looked up by digest.
    Existing tokens are hashed by the migration and keep working.
  • New deploy tokens created without an expiry date now expire after
    RUSTDESK_DEPLOY_TOKEN_TTL_DAYS days (default 365; 0 restores never-expiring tokens).
    Existing deploy tokens keep the expiry they had.
  • Pending OIDC logins are keyed by a digest of the polling code; an undelivered result is
    encrypted with the application key.
  • Address-book peer password and hash are encrypted with the application key. The client
    API returns exactly the same values as before. See "Before you upgrade" about the key.

Standalone web viewer removed from the public origin (Medium)

The bare development page /assets/webclient/src/ui/viewer.html now returns 404 from the
runtime image; the in-console Connect flow (which injects the server's own connection
settings) is unaffected. The standalone page, where it is still used for development, always
requires an encrypted, key-verified session and no longer takes the server host or key from the
URL. The injected viewer configuration is also escaped more strictly, and the viewer iframe no
longer requests clipboard-read permission it never used.

Login hardening (Medium / Low)

  • Per-account ceiling: failed password attempts are counted per account name across all
    source addresses (default 20 per 15 minutes, shared by the client API and the admin console) and
    refused beyond that — checked before any LDAP bind, so this server cannot be used to lock
    Active Directory accounts faster than the ceiling allows. A successful sign-in resets the count.
    Tune with RUSTDESK_LOGIN_ACCOUNT_MAX_FAILURES (0 disables) and
    RUSTDESK_LOGIN_ACCOUNT_DECAY_MINUTES.
  • IPv6 callers are rate-limited per /64 instead of per address.
  • No account-state disclosure before a correct password: "Account disabled", "Account not
    verified" and "must sign in via SSO" are shown only after the right password; unknown accounts
    cost the same hashing time as known ones.
  • Console honours email login verification: accounts whose login verification is set to
    email now receive a code by email when signing in to the admin console too (previously only the
    RustDesk client asked for it). Mail must be working for those accounts; if the code cannot be
    sent, sign-in fails closed. Before upgrading, check that mail delivery works for any
    administrator whose login verification is "email"
    ; if an administrator is locked out,
    php artisan rustdesk:admin:reset <username> --generate --clear-2fa (inside the container)
    sets a new password and turns login verification off for that account.
  • TOTP codes are single-use: a code (or an older one) that was already accepted cannot be
    replayed within its validity window, in the client and in the console.

Browser security headers (Low)

Console responses now carry X-Content-Type-Options: nosniff,
Referrer-Policy: strict-origin-when-cross-origin, X-Frame-Options: SAMEORIGIN and
Content-Security-Policy: frame-ancestors 'self', plus Strict-Transport-Security on HTTPS
requests only. The in-console viewer (same origin) still works.


New settings

Variable Default Meaning
RUSTDESK_DEPLOY_TOKEN_TTL_DAYS 365 Lifetime of a new deploy token created without an expiry date; 0 = never expires
RUSTDESK_LOGIN_ACCOUNT_MAX_FAILURES 20 Failed first-factor attempts per account (all sources) before refusing; 0 disables
RUSTDESK_LOGIN_ACCOUNT_DECAY_MINUTES 15 Window for the per-account ceiling

TRUSTED_PROXIES=* remains the bundled default. As before, it is safe only when the application
port is reachable exclusively through a proxy that overwrites X-Forwarded-For; every IP-based
control (login limits, API-key and recording-upload IP allowlists) depends on it. See
Wiki/core/15-security.md → Inbound Proxy Boundary.

Not changed in this release

  • The web viewer's managed mode still downgrades to an unverified session when no
    RUSTDESK_PUBLIC_KEY is configured (the diagnostics page warns about it); making that fail
    closed would break deployments without a configured key.
  • A malicious remote machine can still ask the viewer to show its elevation (UAC) credential form,
    and peer clipboard content is applied without a notice — both match the native client and are
    tracked for a later web-client release.