feat: harden production security boundaries
This commit is contained in:
+1
-1
@@ -65,7 +65,7 @@
|
||||
- [x] Сделать seed устойчивым к частично заполненной БД: справочники досеиваются независимо, демо-уловы идемпотентны и принудительно отключены в production; повторный/частичный запуск покрыт конфигурационными и интеграционными проверками.
|
||||
- [ ] Проверить списочные API по требованию раздела 12: пагинация, предсказуемая сортировка и валидация фильтров для справочников, импортов, модерации и внешнего staging.
|
||||
- [ ] Проверить необходимые индексы PostgreSQL и планы запросов для activity, модерации, дедупликации и очистки rate limit; зафиксировать допустимый бюджет запросов пилота.
|
||||
- [ ] Провести security-проверку admin-аутентификации, CORS, security headers, загрузок и управления секретами; вынести допустимые origins в конфигурацию и исключить демонстрационные секреты в production-режиме.
|
||||
- [x] Провести security-проверку admin-аутентификации, CORS, headers, загрузок, контейнерных пользователей и секретов: двойная защита admin web/API, constant-time token, no-store, non-root API/web и отдельные MinIO root/app credentials; остаточные ограничения записаны в `docs/security-review.md`.
|
||||
- [x] Проверить авторизацию повторной загрузки скриншота: используется отдельный одноразовый случайный токен, в БД хранится только SHA-256, UUID заявки недостаточно.
|
||||
- [x] Определить сроки хранения ников, исходных payload, staging-наблюдений, moderation events и submission attempts; добавлены настраиваемая dry-run-first очистка, тест и `docs/data-retention.md`.
|
||||
- [x] Добавить резервное копирование и документированное восстановление PostgreSQL и MinIO: консистентные `pg_dump` и MinIO API mirror, контрольные суммы, runbook и успешный изолированный drill с намеренным удалением данных (6 сентября 2026).
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
# Production security review
|
||||
|
||||
Проверка выполнена 7 сентября 2026 года для закрытой альфы. Она охватывает код и Compose-конфигурацию; firewall, SSH, DNS и фактические права файлов проверяются отдельно на целевом сервере.
|
||||
|
||||
## Закрытые пункты
|
||||
|
||||
| Область | Реализация |
|
||||
|---|---|
|
||||
| Внешняя поверхность | наружу публикуются только Caddy `80/443`; PostgreSQL, API, web и MinIO находятся во внутренних сетях |
|
||||
| Admin web/API | `/admin/*` и `/api/v1/admin/*` требуют Caddy Basic Auth; API дополнительно требует длинный bearer token |
|
||||
| Сравнение токена | 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` и `/api/v1/admin/catch-reports` должен вернуть `401` от Caddy.
|
||||
4. С Basic Auth, но без bearer token административный API должен вернуть `401` от FastAPI.
|
||||
5. Проверить security headers через `curl -I https://rf4spotter.ru/`.
|
||||
6. Убедиться, что `https://files.rf4spotter.ru/` не открывает Console, list buckets или анонимную запись.
|
||||
7. После проверки удалить команды с секретами из shell history либо вводить их через защищённый password manager.
|
||||
Reference in New Issue
Block a user