mistgate Документация

Безопасность

Кто что может в админке, как устроены вход, повторное подтверждение и сессии, как панель прячется за сайтом-ширмой, что лежит в каталоге данных и как вернуть доступ.

На этой странице

Эта страница о защите админки: роли, вход, повторное подтверждение входа, сессии, капча, журнал аудита, сайт-ширма перед всем остальным, каталог данных и возвращение доступа с сервера панели. Как сообщить об уязвимости — в конце страницы.

Роли админов#

В админке три роли. Каждый запрос проверяется по роли для конкретной процедуры; процедура без правила доступна только владельцу.

Роль Может
Владелец Всё: ноды (добавление, вывод из флота, логи), профили и где они работают, DNS-пресеты, исправления доктора, обновления, WARP, API-токены и одобрения, журнал аудита, настройки безопасности и оформления.
Помощник Повседневную работу: пользователи (создание, изменение, включение и отключение, продление, сброс трафика, удаление, устройства, ссылка подписки), группы, настройки подписок, настройки ноды и перезапуск профилей на ноде, заглушка алертов, «Проверить сейчас», запуск доктора, принятие предупреждений доктора.
Только чтение Чтение: обзор, ноды, профили (секреты скрыты), группы, пользователи, события, алерты, проверки, отчёты доктора, страница «Обновления». И свой аккаунт: passkey, пароль, сессии.
Важно

сейчас у панели один админ — владелец, созданный при настройке: добавить помощника или админа только для чтения пока нельзя. Но роли уже действуют для API-токенов: их профили работают как эти роли.

Вход#

Владелец создаётся по одноразовой ссылке, которую печатает mistgate setup (действует 30 минут; повторный setup, пока админа нет, выдаёт новую ссылку, а старая перестаёт работать). Владелец выбирает один из двух способов входа и позже может добавить второй в Настройки → Безопасность.

Passkey. Вход по отпечатку пальца, лицу или аппаратному ключу. Поля логина нет: браузер предлагает passkey, которые у него есть для этой панели. Подтверждение пользователя (PIN или биометрия) нужно каждый раз. Passkey привязан к адресу админки (к WebAuthn RP, заданному при настройке) и работает только на нём.

Пароль и код из приложения. Логин (от 3 до 64 символов из a-z 0-9 . _ @ -), пароль (не короче 12 символов и не длиннее 256 байт) и 6-значный код из приложения-аутентификатора (по времени, шаг 30 секунд). Пароли хранятся как хеши argon2id; секрет аутентификатора зашифрован мастер-ключом, поэтому панель без мастер-ключа такой способ входа не предложит. Каждый код срабатывает один раз.

Ограничения входа по паролю:

  • 5 неудачных попыток для одного логина за час закрывают этот логин на 15 минут, даже для верных данных.
  • 10 неудачных попыток с одного адреса (IPv4 или IPv6 /64) за час, для любых логинов, закрывают этот адрес на 15 минут.
  • Для несуществующего логина ответ такой же, поэтому неудачи не выдают, какие логины есть.
  • Вход, настройка и повторное подтверждение ещё и ограничены по частоте с одного адреса (сначала до 10 запросов подряд, затем один раз в 3 секунды).

В Настройки → Безопасность админ управляет своим входом:

  • Passkey: добавить (нужно повторное подтверждение) или удалить (нужно повторное подтверждение; последний способ входа удалить нельзя).
  • Пароль и код: добавить как запасной вход рядом с passkey, Сменить пароль (нужны повторное подтверждение и текущий пароль; другие сессии завершатся), Перепривязать приложение для нового телефона (нужно повторное подтверждение; другие сессии завершатся).

Повторное подтверждение входа#

Украденной cookie сессии не должно хватать, чтобы добавить свой passkey, удалить passkey владельца или поменять то, что работает на нодах. Для этих действий нужно подтверждение входа не старше 5 минут:

  • добавление и удаление passkey;
  • завершение другой сессии или всех остальных;
  • смена пароля, привязка приложения-аутентификатора;
  • изменение настроек капчи;
  • запуск, пауза, продолжение и отмена раскатки, откат ноды, повторное чтение папки релиза;
  • регистрация, импорт и удаление аккаунта WARP;
  • создание и отзыв API-токена, одобрение изменения от агента.

Сам вход считается подтверждением, поэтому «войти и сразу добавить passkey» ничего лишнего не спросит. Иначе админка покажет Подтверди, что это ты: используйте passkey или введите код из приложения. Код для подтверждения должен быть новее того, с которым вы вошли (подождите следующего 30-секундного шага). Пять неверных подтверждений закрывают повторное подтверждение на 15 минут. API-токен никогда не проходит повторное подтверждение; см. API.

Сессии#

  • Cookie сессии — __Host-sid: только по HTTPS, недоступна скриптам, отправляется только самой панели (SameSite=Strict).
  • Сессия заканчивается после 12 часов без активности и не позже чем через 30 дней.
  • Настройки → Сессии показывает свои сессии админа с адресом и браузером. Завершить завершает одну (чужую, не текущую — с повторным подтверждением); Завершить остальные завершает все прочие (с повторным подтверждением).
  • Смена пароля, перепривязка приложения и mistgate auth reset-login тоже завершают другие сессии.

Cloudflare Turnstile#

Владелец может поставить проверку Cloudflare Turnstile перед страницами входа и настройки: Настройки → Безопасность → Проверка Cloudflare на входе.

  1. Создайте виджет Turnstile в панели Cloudflare для домена панели.
  2. Введите Site key и Secret key. Secret key только для записи: панель хранит его зашифрованным мастер-ключом и больше не показывает.
  3. Нажмите Проверить и включить и пройдите появившуюся проверку. Панель спросит у Cloudflare, подходит ли secret key к токену, который выдал виджет; до этого ничего не сохраняется.

Когда проверка включена, каждое начало входа (по passkey или паролю) и настройки требует свежего токена от виджета; второй шаг входа по passkey — нет. Если Cloudflare недоступен, войти нельзя. Скрипт Cloudflare страницы админки загружают, только пока проверка включена.

Если проверка не пускает никого (Cloudflare недоступен, ключи неверны), выключите её на сервере панели; ключи останутся сохранены:

sh
mistgate auth turnstile off

Журнал аудита#

Настройки → Аудит (только владелец) показывает, кто что сделал и откуда, сначала новое.

  • Источник аудита: «Все источники», «Панель», «Бот», «MCP», «API».
  • Что показать: «Всё», «Входы» (настройка, вход и выход, блокировки, повторное подтверждение, капча, passkey, пароли, сессии), «Изменения» (пользователи, группы, профили, устройства, DNS-пресеты, ноды, WARP, обновления, исправления доктора, токены, одобрения, настройки), «Неудачи» (неудачные, отклонённые и заблокированные попытки любого рода).
  • В каждой строке — кто, действие, параметры, результат и адрес клиента. Секретов в параметрах не бывает.
  • Токен показан как «API-токен <имя>» или «токен MCP <имя>». Удачные чтения токеном пишутся не чаще раза в минуту на процедуру; изменения и отказы — всегда.
  • Действия из командной строки (mistgate auth ...) тоже попадают в журнал.

Панель журнал аудита не чистит.

Сайт-ширма и скрытая админка#

Всё на публичном адресе, что не админка, не подписка и не точка подключения агентов, отвечает сайтом-ширмой.

  • Ширма. По умолчанию — встроенная страница «Coming soon» на /, robots.txt, который закрывает сайт от известных ИИ-краулеров, и одна и та же страница 404 для любого другого пути и любого метода, кроме GET и HEAD. Встроенная страница одинакова во всех установках и потому узнаваема: отдавайте свой сайт через serve --decoy-dir <каталог>. Файлы отдаются без Last-Modified и ETag; имена, начинающиеся с точки, не отдаются; 404.html и 429.html в каталоге заменяют встроенные страницы ошибок.

  • Админка доступна одним из трёх способов, который выбирается при mistgate setup:

    • секретный префикс пути (по умолчанию): https://panel.example.com/<24 случайных символа>/;
    • секретное имя хоста: setup --admin-host <имя>;
    • отдельный адрес: setup --admin-listen 127.0.0.1:8081. Он работает по обычному HTTP, поэтому вешайте его на loopback и заходите через SSH-туннель.

    Неверный префикс или другое имя хоста получают сайт-ширму, необычная форма пути — её 404. Админка никогда не отвечает перенаправлением, которое могло бы выдать префикс.

  • Подписки живут под другим секретным префиксом. Неизвестный токен подписки получает ту же 404, что и неизвестный путь, а каждая 404 отвечает не быстрее 8 мс, так что угаданный токен не отличить от неверного пути ни по содержимому, ни по заголовкам, ни по времени.

  • Точку подключения агентов выбирает секретное имя в TLS (SNI): случайный поддомен домена панели, которому не нужна DNS-запись. Панель отвечает на него сертификатом своего собственного CA, который не попадает в публичные журналы сертификатов и не называет продукт. Клиент без этого имени видит ширму.

  • Ограничения частоты на сеть клиента (адрес IPv4 или IPv6 /64): 10 запросов в секунду (до 60 подряд) на публичном сайте и подписках, 30 в секунду (до 200 подряд) на админке, 5 в секунду (до 30 подряд) на точке подключения агентов. Сверх лимита отвечает страница 429 в стиле ширмы с Retry-After.

  • Страницы админки отдаются со строгой Content-Security-Policy, без встраивания в чужие фреймы, без Referer, с noindex и no-store, а по HTTPS — с HSTS.

Настройки → Домены показывает владельцу адрес админки и основу ссылок подписки. В обоих есть секретная часть: не публикуйте их. За обратным прокси укажите его в serve --trusted-proxy, чтобы панель видела настоящие адреса клиентов (от них зависят ограничения частоты, сессии и журнал аудита). Все флаги — в «Конфигурации».

Каталог данных#

Всё, что знает панель, лежит в её каталоге данных, по умолчанию /var/lib/mistgate (режим 0700):

Путь Что это
master.key 32 случайных байта, режим 0600. Им зашифрованы все хранимые секреты (XChaCha20-Poly1305). Панель умеет читать его и из учётных данных systemd ($CREDENTIALS_DIRECTORY/master.key).
mistgate.db (с -wal и -shm) База SQLite, режим 0600: пользователи, ноды, профили, сессии, журнал аудита и CA панели, закрытый ключ которого зашифрован мастер-ключом.
acme/ Сертификаты Let's Encrypt при serve --acme-domain.
dist/ Пакет релиза агента нод (см. «Обновления»).

Пароли страниц пользователей не хранятся: они выводятся из мастер-ключа. Поэтому новый мастер-ключ меняет пароль каждой страницы и делает нечитаемым каждый хранимый секрет. Потеря каталога данных означает заново подключить каждую ноду (ноды доверяют CA панели) и выдать пользователям новые ссылки.

Резервные копии#

Автоматических бэкапов пока нет; шифрованные бэкапы панели в планах. Делайте копию сами, остановив панель:

sh
systemctl stop mistgate     # имя вашего unit
tar czf mistgate-backup-$(date +%F).tgz -C /var/lib mistgate
systemctl start mistgate
Внимание

в копии лежит мастер-ключ: у кого она, тот прочтёт все секреты панели. Храните её зашифрованной и не на сервере панели.

Чтобы восстановить, остановите панель, верните каталог на место (владелец — пользователь, от которого работает панель, режим 0700) и запустите её.

Возвращение доступа#

Всё это выполняется на сервере панели от пользователя, который может читать каталог данных (обычно root). Команды работают и при запущенной, и при остановленной панели. Если данные не в /var/lib/mistgate, добавьте --data-dir <каталог>. reset-login нужен мастер-ключ: если он лежит не в каталоге данных, а передаётся панели как учётные данные systemd, укажите в CREDENTIALS_DIRECTORY каталог, где лежит master.key.

Потерян телефон (вход по паролю).

sh
mistgate auth reset-login <логин>

Команда печатает новый пароль и новый ключ аутентификатора: QR-кодом прямо в терминале (для тёмного фона; для светлого добавьте --qr-invert), текстом группами по четыре символа и ссылкой otpauth://. Она снимает блокировки логина и повторного подтверждения и завершает все сессии этого админа. Passkey остаются. Войдите с логином, паролем и кодом, затем задайте свой пароль в Настройки → Безопасность. Пароль показывается один раз и нигде не хранится в открытом виде.

Не осталось ни одного passkey (админ входил только по passkey). Без аргументов команда показывает список админов; дайте нужному вход по паролю по его идентификатору:

sh
mistgate auth reset-login
mistgate auth reset-login <новый логин> --admin <id админа>

Затем войдите по паролю и удалите потерянный passkey в Настройки → Безопасность.

Капча не пускает: mistgate auth turnstile off.

Потерян адрес админки: запустите mistgate setup ещё раз. Команда сохранит существующие настройки и напечатает адрес админки.

Чего никогда не видят API-токены и MCP#

API-токены и MCP-сервер ходят в панель через те же процедуры, что и админка, но токену разрешён только фиксированный список процедур, и ни одна из них не возвращает учётных данных:

  • ссылки подписки, пароли страниц пользователей, ключи и конфигурации устройств;
  • аккаунты и ключи WARP, секреты профилей (они приходят скрытыми);
  • токены, одобрения, сессии, passkey и настройки безопасности.

Токен никогда не проходит повторное подтверждение, поэтому процедуры, которым оно нужно, для токенов закрыты — кроме как через план MCP, одобренный владельцем. Каждый вызов токеном записывается в журнал аудита. Давайте каждому скрипту и агенту самый узкий профиль, которого хватает. Подробности: API, MCP.

Как сообщить об уязвимости#

Сообщайте закрыто через GitHub: откройте вкладку Security репозитория и выберите Report a vulnerability. Не открывайте об этом публичный issue. Что считается уязвимостью и что нет, перечислено в SECURITY.md в репозитории.

Править страницу на GitHub