--- date: 2026-04-30 type: audit tags: [rustdesk, security, audit, hardening] --- # RustDesk pre-production audit + fixes ## Контекст Перед запуском RustDesk-сервера в продакшн (для удалённого доступа клиентских организаций + личного использования) — системный аудит security, reliability, operations. Findings + примененные fixes. ## Findings & fixes ### 🔴 Critical (исправлено) #### 1. Права на критичные файлы 644 → 600/640 **Что было:** все sensitive файлы на LXC 116 были world-readable (`-rw-r--r--`): - `/var/lib/rustdesk-server/id_ed25519` (**приватный ключ сервера**) - `/var/lib/rustdesk-server/id_ed25519.pub` - `/var/lib/rustdesk-server/db_v2.sqlite3*` (hbbs БД с peers UUID) - `/var/lib/rustdesk-api/data/rustdeskapi.db` (хеши паролей юзеров, токены сессий) - `/var/lib/rustdesk-api/conf/config.yaml` (содержит **JWT secret** и `key`) **Риск:** при компрометации любого non-root юзера на LXC 116 → leak приватного ключа сервера → весь парк клиентов перестаёт быть приватным; возможность подделки JWT и login as admin. **Fix (2026-04-30):** ```bash chmod 600 /var/lib/rustdesk-server/id_ed25519* chmod 640 /var/lib/rustdesk-server/db_v2.sqlite3* chmod 640 /var/lib/rustdesk-api/data/rustdeskapi.db chmod 640 /var/lib/rustdesk-api/conf/config.yaml ``` #### 2. Нет logrotate для rustdesk-логов на 2GB-диске **Что было:** `/var/log/rustdesk-server/hbbs.log` ~260KB и rosт каждый день. На 2GB-диске LXC 116 (где уже 55% used) логи зальют диск за пару месяцев → сервер ляжет. **Fix (2026-04-30):** `/etc/logrotate.d/rustdesk`: ``` /var/log/rustdesk-server/*.log /var/log/rustdesk-server/*.error /var/log/rustdesk-api/*.log /var/log/rustdesk-api/*.error { daily rotate 14 compress delaycompress notifempty missingok copytruncate su root root } ``` #### 3. Нет авто-бэкапа БД и ключей **Что было:** одна вручную сделанная копия `/root/rustdesk-backup-20260428-1134/`. Если завтра LVM упадёт — теряем весь стейт (peers, users, ключи). **Fix (2026-04-30):** cron daily 03:00 → `/usr/local/bin/rustdesk-backup.sh`: - tar.gz в `/root/rustdesk-backups/rustdesk-YYYYMMDD.tar.gz` - ключи + обе БД + config.yaml + systemd overrides - retention 30 дней (find -mtime +30 -delete) - chmod 600 на каждый tarball **TODO:** доставить копии бэкапа на ArtLeon (off-site) через NetBird/rsync. ### 🟡 Medium (исправлено) #### 4. Нет rate-limit на login → brute-force admin password **Что было:** `https://remot.dttb.ru/api/admin/login` принимал безlimit запросы. С учётом стандартного pw `1qaz!QAZ` — кто-то с словарём найдёт его за час. **Fix (2026-04-30):** в NPM `/data/compose/2/data/nginx/custom/http.conf`: ```nginx limit_req_zone $binary_remote_addr zone=adminlogin:10m rate=5r/m; limit_req_zone $binary_remote_addr zone=apilogin:10m rate=10r/m; ``` В Proxy Host 14 advanced_config: ```nginx location = /api/admin/login { limit_req zone=adminlogin burst=3 nodelay; proxy_pass http://10.0.0.244:21114; ... } location = /api/login { limit_req zone=apilogin burst=5 nodelay; proxy_pass http://10.0.0.244:21114; ... } ``` **Verified:** после 4 быстрых попыток — 503 от NPM. На уровне rustdesk-api также `ban-threshold: 5` забанит user-account на ~1 час. **Грабли при настройке:** `limit_req_zone` нельзя класть в `server`-контекст — только `http`. Первая попытка положить в advanced_config привела к удалению NPM proxy_host/14.conf и обвалу `remot.dttb.ru`. Восстановилось через disable/enable + переноса zone в http.conf. ### 🟡 Medium (отложено) #### 5. NC public-link без пароля + содержит RustDesk2.toml с key **Что было:** `https://dttb.ru/s/wPm8oaiFEyz7Ywx` без пароля и без expiration. ZIP внутри содержит `key=R0lA4r77...`. Любой нашедший ссылку может зарегистрировать peer'а на нашем сервере. **Status:** **Nextcloud-AIO сейчас лежит** (502 from NPM upstream), новую share создать не получается. Спавнен отдельный task на восстановление NC. После — пересоздать share с паролем + 30 дней expiration. **Митigation в текущем виде:** `MUST_LOGIN=Y` отбивает входящие connections к незалогиненным peers. Кто-то регистрируется как peer — heartbeat-флуд возможен, но connections не пройдут. #### 6. Security headers не наследуются в location / **Что было:** HSTS, X-Frame-Options, X-Content-Type-Options, Referrer-Policy не появляются в response от `https://remot.dttb.ru/_admin/`. **Корневая причина:** NPM в template для Proxy Host генерит `location /` со встроенным `add_header X-Served-By` (через include `proxy.conf`). По правилу nginx — если в location есть **хоть один** add_header, наследование от server-block отключается. Мои `add_header` в advanced_config (server-level) не применяются к location /. **Fix-варианты (выбран wait):** - (a) Patch NPM template `/etc/nginx/conf.d/include/proxy.conf` чтобы добавить headers — теряется при container recreate - (b) Использовать `more_set_headers` (модуль ngx_headers_more) — нужно проверить что он есть в openresty - (c) Override `location /` в advanced_config с явными add_header — конфликт с NPM-сгенерированным location / - (d) **Принять как cosmetic** — TLS 1.2/1.3 + LE cert + rate-limit обеспечивают основную защиту; HSTS на server-level записан в nginx.conf (не на response). **Status:** **отложено** как cosmetic. Если будем делать (b) или (a) — отдельной задачей. ### 🟢 Low / Informational | Item | Status | |---|---| | Server header раскрывает `openresty` | Accept (мелкий fingerprinting, не критично) | | `show-swagger: 1` в API | Accept (Олег использует для разработки) | | TLS 1.2 + 1.3, intermediate ciphers | ✅ optimal | | LE cert valid until 28 June 2026 | ✅ auto-renew | | Block Common Exploits (NPM) | ✅ enabled на host 14 | | `block_exploits: true`, `caching_enabled: false` | ✅ verified | | `register: false` в API | ✅ закрытая система | | `ban-threshold: 5`, `captcha-threshold: 3` | ✅ enabled | | `MUST_LOGIN=Y` | ✅ enforced (видно в hbbs.log) | | RustDesk peers версии | 1.4.6 (latest stable) | | Disk LXC 116 free | 826 MB / 2 GB (55% used) — monitoring | | RAM LXC 116 used | 105M / 512M — большой запас | | NPM compose ports 21115-21119 | ✅ exposed после 2026-04-29 update | ## Что осталось сделать (production todo) ### Перед массовым deploy - [ ] Восстановить Nextcloud (отдельный task) - [ ] Создать share-link с паролем + expiration после восстановления NC - [ ] Создать минимум 2 группы в `/_admin/` (например `НИИКН`, `Клиенты-Internal`) - [ ] Настроить **Configuration Strategy** в админке lejianwen — push настроек существующим клиентам автоматически - [ ] Off-site бэкап `/root/rustdesk-backups/*.tar.gz` на ArtLeon через rsync over NetBird (cron weekly) ### Полезное (не блокирует prod) - [ ] `more_set_headers` фикс security headers - [ ] fail2ban на NPM access logs (поверх rate-limit) — extra слой против distributed brute-force - [ ] Monitoring: alert на падение rustdesk сервиса (через watchyourlan/zabbix/uptime-kuma) - [ ] Auto-login клиента в API через service-token (упрощает onboarding) - [ ] `rustdesk-utils` 2.x для single-file `rustdesk-licensed-*.exe` deployment ### Долгосрочное - [ ] Через 1-2 месяца — миграция в Docker `lejianwen/rustdesk-server-s6` (Вариант A3) - [ ] HA-схема на втором экземпляре (НИИКН Proxmox) с общей MySQL - [ ] MCP-обёртка поверх Swagger API для управления из Claude Code ## Верификация ```bash # Permissions OK ssh root@10.0.0.250 "pct exec 116 -- ls -la /var/lib/rustdesk-server/id_ed25519" # → -rw------- 1 root root 88 Oct 10 2025 # Logrotate OK ssh root@10.0.0.250 "pct exec 116 -- logrotate -d /etc/logrotate.d/rustdesk" # → "considering log /var/log/rustdesk-..." # Auto-backup ran ssh root@10.0.0.250 "pct exec 116 -- ls -la /root/rustdesk-backups/" # → rustdesk-20260430.tar.gz # Rate-limit работает for i in {1..6}; do curl -ks -o /dev/null -w "%{http_code} " -X POST https://remot.dttb.ru/api/admin/login \ -H "Content-Type: application/json" -d '{"username":"x","password":"y"}' done # → 200 200 200 200 503 503 # Сервер отвечает curl -ksI https://remot.dttb.ru/_admin/ | head -1 # → HTTP/2 200 ``` ## Связанные - [[../projects/dttb/rustdesk-runbook]] — операционный runbook (создан этим audit'ом) - [[2026-04-28-rustdesk-lejianwen-pro-migration]] — миграция с OSS - [[2026-04-29-rustdesk-client-deployment-package]] — пакет установки клиентов - [[../projects/dttb/rustdesk]] — справочник