Skip to content

08 Security

Mikhail Deynekin edited this page Oct 31, 2026 · 1 revision

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

Что панель защищает

Ресурс Как защищён
Ключ API Fornex хранится в файле настроек вне корня сайта; не возвращается ни одним маршрутом; не пишется в журнал
Пароль панели только хэш password_hash(); пустой хэш означает «вход запрещён»
Токены API в базе лежат префикс и хэш; полный токен показывается один раз при выпуске
Запись в зону только по id, только через план, снимок перед каждым изменением
Журнал каждая попытка, сухой прогон и отказ с причиной

Два способа входа

  1. Сессия. Логин и пароль, cookie HttpOnly, SameSite=Lax, Secure при HTTPS. Ограничение попыток: 10 неудач с адреса за 15 минут → 429.
  2. Bearer-токен. Для скриптов. По умолчанию «только чтение»; запись — только если токен выпущен с этим правом. Токен проверяется по хэшу, отзыв действует сразу.

CSRF-токен нужен для пишущих запросов из браузера. Скрипту он не нужен: у него нет сессии, которую можно угнать.

Доверенный адрес

AUTO_LOGIN_IP выдаёт сессию без пароля с одного адреса — те же права, что у обычного входа, включая запись. Механизм существует для рабочего места внутри своей сети.

  • Оставляйте пустым, если сеть и адрес не ваши целиком.
  • Вход пишется в журнал событием auth.autologin с автором panel:autologin, чтобы «кто вошёл без пароля» не было тайной.
  • Адрес клиента берётся из соединения; X-Forwarded-For учитывается только когда запрос приходит с loopback (nginx на том же хосте), поэтому подделать адрес заголовком нельзя.

Ограничение доступа по адресам

Панель — административная поверхность с ключом DNS за ней. Рекомендуется закрыть её списком разрешённых адресов на веб-сервере:

allow 192.0.2.0/24;
allow 2001:db8::/32;
deny all;

Ограничения частоты на самом API нет — его ставит веб-сервер.

Секреты в отчётах и журнале

Правило проекта: имя, тип, место, маска. Значение — никогда.

  • GET /api/meta отдаёт адрес API, таймауты, типовой IP и список типов записей — не ключ.
  • GET /api/tokens показывает префикс, дату, право записи — не значение.
  • Журнал хранит действие, объект и итог; ключ и пароль в него не попадают.
  • Сообщение об ошибке от Fornex передаётся как есть, но ключ в нём не появляется: он уходит только в заголовке запроса.

Снимки зоны

Снимок — BIND-файл и JSON с идентификаторами записей. Он не содержит секретов, но содержит полную зону: поддомены, адреса, TXT-записи подтверждений. Поэтому SNAPSHOT_DIR — вне корня сайта и не отдаётся по HTTP.

Что делать при подозрении на утечку ключа

  1. Перевыпустить ключ в кабинете Fornex (старый отозвать).
  2. Заменить FORNEX_API_KEY в файле настроек, перезагрузить PHP-FPM.
  3. Проверить журнал: php backend/bin/fornex audit --limit=100 — искать неожиданные действия.
  4. Проверить выпущенные токены и отозвать лишние: GET /api/tokens, DELETE /api/tokens/{id}.
  5. Сменить пароль панели: новый password_hash(), перезапуск PHP-FPM.

Токены: практика

Задача Право
Мониторинг зоны, чтение записей только чтение
Скрипт, который правит записи по расписанию запись, отдельным токеном
Одноразовая проверка токен с записью, отозванный после

Токен удобнее держать в файле с правами 600 и передавать в заголовке Authorization.

Сообщить об уязвимости

Приватно, через GitHub → Security → Advisories. Не в issue: публичный отчёт до исправления — это подсказка тому, кто ищет цель. Полные правила — в SECURITY.md.

Clone this wiki locally