Corp/docs/registration-network-policy.md
Игорь Надеин e72a039744
All checks were successful
Deploy production / deploy (push) Successful in 10m51s
Match registration UI to server-side LAN access policy
2026-09-16 13:31:57 +03:00

5.4 KiB
Raw Blame History

Регистрация только из локальной сети

Переключатель в серверном backend .env (не frontend и не секрет runner):

REGISTRATION_LAN_ONLY_ENABLED=true

Если переменной нет, она пустая или равна false, ограничение выключено. Включает его только true (регистр и пробелы по краям не важны). После изменения .env нужен перезапуск процессов Django или штатный деплой: настройки читаются при старте. Сам .env в Git не добавляется.

При включении оба адреса /api/auth/register/ и /api/v1/auth/register/ принимают регистрацию только из 172.11.0.0/23. Снаружи возвращается HTTP 403 с понятным сообщением до валидации, создания пользователя, отправки письма и LDAP. Вход, OIDC, восстановление пароля и подтверждение уже отправленного письма этим ограничением не затрагиваются.

Frontend запрашивает /api/auth/registration-availability/ (есть и alias /api/v1/auth/registration-availability/). Ответ {"registration_allowed": true/false} использует ту же проверку, что POST регистрации, не содержит IP или конфигурацию сети и имеет Cache-Control: private, no-store. Ссылка «Создать аккаунт» видна только после разрешающего ответа. При прямом открытии /register извне показывается объяснение вместо формы. Во время проверки и при ошибке форма скрыта; при ошибке можно повторить запрос. Проверка повторяется при возврате фокуса, восстановлении страницы и соединения. Авторитетной защитой остаётся POST API — скрытие кнопки её не заменяет.

Адрес клиента и границы доверия

Рабочий маршрут: клиент → Synology 172.11.1.254 → nginx CORP → ASGI на loopback. Оба прокси должны дописывать настоящий IP своего непосредственного клиента в X-Forwarded-For. На CORP это $proxy_add_x_forwarded_for.

Проверка идёт справа налево, пропуская только явно доверенные прокси (127.0.0.1, ::1, 172.11.1.254), до первого недоверенного адреса. Подставленный клиентом префикс не влияет на решение. Другие заголовки адреса не используются. Если запрос пришёл от доверенного прокси, но адрес клиента отсутствует, повреждён или состоит только из адресов прокси, доступ запрещён. Router 172.11.0.1, прокси и network/broadcast адреса не считаются пользователями. 172.11.0.0/16 и произвольные частные сети не разрешены.

Нельзя открывать backend-порты наружу или добавлять всю LAN в доверенные прокси. Если пограничный NAT скрывает внешний адрес за другим LAN-IP, сначала исправить передачу исходного адреса/добавить этот шлюз в исключения: по одному IP приложение не отличит такой запрос от локального. Список прокси не является списком клиентов.

16 сентября 2026 проверены реальные заголовки через Synology:

  • обычный LAN-запрос: 172.11.1.128, 172.11.1.254;
  • запрос с подставленным XFF: 172.11.0.123, 172.11.1.128, 172.11.1.254.

Проверка

pytest tests/api/auth/test_registration_network.py проверяет оба режима, обе версии API, успешную регистрацию, отсутствие побочных эффектов при отказе, подмену заголовков, IPv6, повреждённые цепочки и доступность остальных auth API. В production проверять без создания учёток: POST пустого JSON {} из LAN должен вернуть 400 (валидация), извне при включённом флаге — 403.

Отключение: REGISTRATION_LAN_ONLY_ENABLED=false и перезапуск Django/деплой. Это снова разрешит регистрацию извне; другие настройки авторизации не меняются.

Основа реализации: DRF permissions и nginx proxy_add_x_forwarded_for.