[SECURITY] Caddy: /trade-in/api/v1/admin/* доступен снаружи анонимно до guard'а — нет среза админского префикса на периметре #3360

Closed
opened 2026-09-05 18:13:24 +00:00 by bot-backend · 1 comment
Collaborator

Находка доводки PR #3352 (401-оракул rbac). caddy/sites/apps.caddy:~200handle /trade-in/api/* { uri strip_prefix /trade-in; reverse_proxy tradein-backend:8000 { header_up -X-Authenticated-User } }, весь /trade-in-блок стоит ВЫШЕ import caddy/users.caddy.snippet (у trade-in своя сессионная авторизация). Следствие: внешний gendsgn.ru/trade-in/api/v1/admin/<имя> доходит до rbac_guard анонимно. Защита в глубину работает (guard отдаёт 401/403), но:

  1. после #3352 аноним отличает существующую admin-ручку (401) от несуществующей (404) → перебор имён admin-API выполним извне;
  2. любая будущая ошибка в guard'е (порядок веток, регрессия) выставит admin-API наружу без второго рубежа.

Лечение

Срез на периметре: для path /trade-in/api/v1/admin/*/trade-in/api/v1/team/**, если team-API не нужен снаружи — проверить, кто его зовёт: фронт кабинета менеджера ЗОВЁТ team-API из браузера, значит team остаётся) — respond 404 для внешнего трафика, либо remote_ip allowlist docker-сети/VPN. Проверить, кто реально ходит в admin-API снаружи (фронт /trade-in/admin/** в браузере? тогда срез невозможен без VPN — тогда хотя бы единый 404 для анонима на admin-префиксе в самом guard'е).

Приёмка

  • Аноним снаружи: /trade-in/api/v1/admin/<существующая> и /<несуществующая> дают одинаковый ответ (404);
  • Залогиненный admin из браузера — admin-UI работает как раньше (смоук);
  • Смоук периметра дополнен парой admin-путей.

Refs #3324, PR #3352, #3316.

Находка доводки PR #3352 (401-оракул rbac). `caddy/sites/apps.caddy:~200` — `handle /trade-in/api/* { uri strip_prefix /trade-in; reverse_proxy tradein-backend:8000 { header_up -X-Authenticated-User } }`, весь `/trade-in`-блок стоит ВЫШЕ `import caddy/users.caddy.snippet` (у trade-in своя сессионная авторизация). Следствие: внешний `gendsgn.ru/trade-in/api/v1/admin/<имя>` доходит до `rbac_guard` анонимно. Защита в глубину работает (guard отдаёт 401/403), но: 1. после #3352 аноним отличает существующую admin-ручку (401) от несуществующей (404) → перебор имён admin-API выполним извне; 2. любая будущая ошибка в guard'е (порядок веток, регрессия) выставит admin-API наружу без второго рубежа. ## Лечение Срез на периметре: для `path /trade-in/api/v1/admin/*` (и `/trade-in/api/v1/team/**`, если team-API не нужен снаружи — проверить, кто его зовёт: фронт кабинета менеджера ЗОВЁТ team-API из браузера, значит team остаётся) — `respond 404` для внешнего трафика, либо `remote_ip` allowlist docker-сети/VPN. Проверить, кто реально ходит в admin-API снаружи (фронт `/trade-in/admin/**` в браузере? тогда срез невозможен без VPN — тогда хотя бы единый 404 для анонима на admin-префиксе в самом guard'е). ## Приёмка - [ ] Аноним снаружи: `/trade-in/api/v1/admin/<существующая>` и `/<несуществующая>` дают одинаковый ответ (404); - [ ] Залогиненный admin из браузера — admin-UI работает как раньше (смоук); - [ ] Смоук периметра дополнен парой admin-путей. Refs #3324, PR #3352, #3316.
Author
Collaborator

Прод-приёмка PR #3371 (05.09 20:40 UTC, BUILD_SHA=357c434): аноним снаружи — /trade-in/api/v1/admin/proxies (существует) → 404, /trade-in/api/v1/admin/users (нет) → 404, тела одинаковы — существование admin-ручек не перебирается; под admin — /admin/proxies → 200, страница /trade-in/scrapers → 200 (админ-UI жив). Смоук периметра scripts/smoke-mera-perimeter.shALL CHECKS PASSED (включая новую admin-пару и исправленный путь истории из #3374). TRADEIN_INTERNAL_AUTH_SECRET на проде непустой (64) — внутренний гейт #2213 держит остаточный оракул внутри docker-сети.

Прод-приёмка PR #3371 (05.09 20:40 UTC, `BUILD_SHA=357c434`): аноним снаружи — `/trade-in/api/v1/admin/proxies` (существует) → **404**, `/trade-in/api/v1/admin/users` (нет) → **404**, тела одинаковы — существование admin-ручек не перебирается; под admin — `/admin/proxies` → 200, страница `/trade-in/scrapers` → 200 (админ-UI жив). Смоук периметра `scripts/smoke-mera-perimeter.sh` → **ALL CHECKS PASSED** (включая новую admin-пару и исправленный путь истории из #3374). `TRADEIN_INTERNAL_AUTH_SECRET` на проде непустой (64) — внутренний гейт #2213 держит остаточный оракул внутри docker-сети.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: lekss361/gendesign#3360
No description provided.