Files
rf4-spotter/docs/security-review.md
ik c6fdc969c2
CI / backend-and-migrations (push) Canceled after 0s
CI / astro-build (push) Canceled after 0s
CI / compose-e2e (push) Canceled after 0s
fix: separate admin page and API authentication
2026-09-09 07:29:39 +07:00

41 lines
5.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Production security review
Проверка выполнена 7 сентября 2026 года и актуализирована для открытой альфы. Она охватывает код и Compose-конфигурацию; firewall, SSH, DNS и фактические права файлов проверяются отдельно на целевом сервере.
## Закрытые пункты
| Область | Реализация |
|---|---|
| Внешняя поверхность | наружу публикуются только Caddy `80/443`; PostgreSQL, API, web и MinIO находятся во внутренних сетях |
| Admin web/API | `/admin/*` требует Caddy Basic Auth; `/api/v1/admin/*` требует длинный Bearer-токен в FastAPI. Схемы разделены по маршрутам, поскольку используют один заголовок Authorization (T02, 9 сентября) |
| Сравнение токена | constant-time `hmac.compare_digest` |
| CORS | production принимает только явно заданные HTTPS origins, wildcard запрещён конфигурацией |
| Чувствительные ответы | административные ответы и создание заявки получают `Cache-Control: no-store` |
| Browser headers | HSTS, `nosniff`, restrictive referrer/permissions, anti-framing CSP/X-Frame-Options и COOP |
| Скриншоты | MIME/расширение/фактический формат, лимит размера и пикселей, повторное кодирование без EXIF, одноразовый upload token |
| MinIO | Console не опубликована; root credentials отделены от application credentials и не передаются API |
| Секреты | production fail-fast отклоняет короткие/демонстрационные значения; `.env.production` исключён из Git и должен иметь mode `0600` |
| Контейнеры | API и web запускаются непривилегированными пользователями; для всех сервисов включён `no-new-privileges` |
| Логи | query string, IP, Authorization и payload не журналируются; известные формы секретов редактируются |
| Персональные данные | действует документированная retention-очистка, причём backup выполняется раньше удаления |
## Остаточные риски открытой альфы
- Basic Auth и bearer token общие для всех модераторов: персональная атрибуция и отзыв одной учётной записи отсутствуют.
- Нет MFA и отдельного identity provider; admin credentials следует передавать только ограниченному числу операторов и ротировать при любом подозрении.
- Application user MinIO имеет встроенную политику `readwrite`; сейчас в инстансе используется один прикладной bucket. Перед появлением других bucket нужна отдельная bucket-scoped policy.
- Пользователь `rf4spotter`, запускающий Docker/systemd, фактически обладает высокими правами через Docker socket. SSH к нему должен быть ограничен ключами и firewall/VPN.
- Защита от volumetric DDoS и внешний WAF не входят в single-server Compose.
## Проверка на сервере
1. Убедиться, что `ss -lntup` не показывает наружу порты `4321`, `8000`, `9000`, `9001`, `5432`.
2. Проверить `stat -c '%a %U:%G' .env.production`: ожидается `600 rf4spotter:rf4spotter`.
3. Без Basic Auth запрос к `/admin/moderation` должен вернуть `401` от Caddy; с правильным Basic — `200`. Bearer не открывает административную страницу.
4. Admin API без Bearer, с неверным Bearer или только с Basic должен вернуть `401` от FastAPI; правильный Bearer даёт доступ и `Cache-Control: no-store`. Владение API-токеном достаточно для API-доступа; дополнительная Basic-проверка к этим запросам не применяется.
5. Проверить security headers через `curl -I https://rf4spotter.ru/`.
6. Убедиться, что `https://files.rf4spotter.ru/` не открывает Console, list buckets или анонимную запись.
7. После проверки удалить команды с секретами из shell history либо вводить их через защищённый password manager.
Локальная проверка: `sh deploy/test-proxy-routing.sh` запускает временный Caddy с production-маршрутами перед работающим Compose. `probe-admin-auth.py` читает токен из окружения API-контейнера и не печатает его. Проверяются успешное чтение, отказы и PATCH с невалидным UUID без изменения данных; полный цикл реальной модерации через proxy относится к T06.