Files
md2vk/docs/security.md
T

69 lines
4.7 KiB
Markdown
Raw 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.
# md2vk — Безопасность
## Два уровня доступа
### 1. Внешний — Caddy basic_auth (на vps02)
- Весь https://md2vk.nixg.ru закрыт HTTP Basic Auth.
- Пользователь: **estorozhenko**; пароль — у пользователя, в конфиге только bcrypt-хэш.
- Хэш в Caddyfile: `estorozhenko $2a$14$uzlQxJdcRZJ5gDpGG5B26OXnudIme1IYe7xh0WtDwFtbB6XiiDYTS`
(сгенерирован 2026-09-18 `docker exec caddy caddy hash-password --plaintext '<пароль>'`).
- Без basic auth сервис наружу не отдаётся.
### 2. Внутренний — API-ключ (FastAPI)
- Все эндпоинты `/api/v1/*` (кроме `/health`) требуют API-ключ `md2vk_...`:
- в заголовке `Authorization: Bearer <api_key>` (GET) или в теле `{"api_key": ...}` (POST);
- API-ключ даёт право публиковать, но **не позволяет прочитать VK-токен** (raw токен не возвращается ни одним эндпоинтом).
- Хранится только SHA-256 хэш (`api_key_hash`), сравнение constant-time (`hmac.compare_digest`).
- Пользователь estorozhenko + API-ключ: создаётся скриптом, ключ кладётся в `secrets/estorozhenko_api_key.txt` (не в git).
## Блокировка после 5 неудачных попыток (fail2ban на vps02)
- На vps02 установлен fail2ban (v1.0.2), jail `md2vk`:
- следит за site-логом Caddy: `/opt/caddy/caddy_data/logs/md2vk.access.log` (JSON, все запросы включая 401),
- фильтр `filter.d/caddy-md2vk.conf`: `^.*"request":\{"remote_ip":"<HOST>"[^}]*"host":"md2vk\.nixg\.ru"[^}]*\}.*"status":401`,
- правило: ban IP после **5 неудачных попыток** (`maxretry=5`, `findtime=600`; на 6-й срабатывает),
- наказание: **ban до ручного снятия** (`bantime = -1`),
- действие: `iptables-allports` (цепочка `f2b-md2vk`, REJECT; на Debian 12 транслируется в nftables),
- ignoreip: `127.0.0.1/8 ::1 10.8.0.0/24` (не баним bigbox/vps02).
- **Ручная разблокировка** (на vps02, sudo):
```bash
fail2ban-client -c /etc/fail2ban unban <ip>
fail2ban-client -c /etc/fail2ban status md2vk # проверить
```
- Логи fail2ban: `journalctl -u fail2ban -e` или `/var/log/fail2ban.log`.
## Шифрование VK-токенов
- VK OAuth-токены в БД только в шифрованном виде: **Fernet (AES-128-CBC + HMAC-SHA256)**.
- Ключ — Docker secret `/run/secrets/token_encryption_key` (файл на bigbox: `secrets/token_encryption_key`, не в git).
- Расшифровка только в памяти при публикации.
## Rate limiting
- В конфиге `RATE_LIMIT_PER_MINUTE=10` (запросов/мин на VK-аккаунт).
- In-memory bucket — НЕ реализован (открытая задача).
## Аудит-лог
- Пишется JSONL в `/opt/md2vk/logs/access.{YYYY-MM-DD}.log` (вне контейнера — `logs/` на bigbox).
- Событие на каждый запрос `/api/v1/*`: `ts, ip, method, path, api_key_prefix, user_id, status, success, latency_ms, error`.
- Используется для мониторинга (доступность, успешность, активная сессия) и расследований.
- Caddy на vps02 пишет свой access-лог (используется fail2ban).
## Матрица рисков
| Сценарий | Последствия | Защита |
|---|---|---|
| Утечка .db | Токены зашифрованы | Fernet + Docker secret |
| Утечка API-ключа | Можно постить, но не украсть токен | API-ключ ≠ VK-токен |
| Брутфорс basic auth | Полный доступ к веб-интерфейсу API | fail2ban ban после 5 попыток, ручной unban |
| Перехват HTTP | — | HTTPS (Caddy/Let's Encrypt) |
| Компрометация контейнера | Полный доступ к токенам | read-only rootfs, audit log |
| Отзыв токена VK | Пост не выйдет | VK вернёт ошибку → error_message |
## Правило пользователя
> Никогда не удалять файлы пользователя без явного подтверждения. Пароли и токены не сохранять в коде —
> только через переменные окружения, Docker secrets или файлы, исключённые из git (.gitignore).