Files
md2vk/docs/security.md
T

4.5 KiB
Raw Blame History

md2vk — Безопасность

Два уровня доступа

1. Внешний — Caddy basic_auth (на vps02)

  • Весь https://md2vk.nixg.ru закрыт HTTP Basic Auth.
  • Пользователь: estorozhenko; пароль — у пользователя, в конфиге только bcrypt-хэш.
  • Хэш в Caddyfile: admin $2a$14$T5gAji7gmg1t3Ifxw0CJy.jat9vpFfOiJIE8j5bnHynEVH1q.QTPS (генерируется 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, jail md2vk:
    • следит за логами Caddy (JSON: /var/log/caddy/access.log),
    • фильтр: basic auth failure (401 с "err", absence of "user_id"):
      ^.*"status":401.*
      
    • правило: ban IP после 5 неудачных попыток подряд (maxretry=5, findtime=600),
    • наказание: ban до ручного снятия (bantime = -1),
    • действие: iptables-allports (ban на уровне ядра, DROP).
  • Ручная разблокировка (на vps02, sudo):
    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).