Перейти к содержимому

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

Безопасность Minishop в первую очередь держится на стабильных секретах, корректном разделении публичных доменов и ограниченном доступе к админке.

  • WEBAPP_SESSION_SECRET должен быть постоянным между рестартами, иначе Web App-сессии станут невалидными.
  • WEBHOOK_SECRET_TOKEN защищает вебхук Telegram.
  • PANEL_WEBHOOK_SECRET проверяет входящие события Remnawave Panel. Секрет задается в Remnawave Panel и вставляется в настройки бота.
  • Платежные токены и webhook-секреты храните в .env или настройках админки с учетом доступа к серверу.

Сгенерировать секрет можно так:

openssl rand -hex 32

Апдейты Telegram-бота проходят через ранний anti-flood middleware до sync профиля, проверки каналов и логирования действий, которые обращаются к базе. Профиль по умолчанию специально мягкий: он не должен мешать быстрым обычным нажатиям кнопок, но отбрасывает экстремальные всплески сообщений и callback от одного источника до того, как они разгонят записи в БД, платежные обработчики или Telegram FloodWait.

Настройки доступны в Админка -> Система -> Настройки -> Система -> Telegram антифлуд. Для обычного приватного продающего бота дефолтов достаточно, поэтому они не добавлены в .env.example. Меняйте их только если реальный трафик показывает, что пороги нужно расширить или сузить.

  • TELEGRAM_DROP_NON_PRIVATE_UPDATES=True отбрасывает апдейты из групп и каналов до дорогих middleware. Оставляйте включенным, если бот не должен работать вне приватных чатов.
  • TELEGRAM_ANTIFLOOD_ENABLED=True включает per-user/per-chat лимиты. Значение 0 у отдельного числового лимита отключает только этот лимит.
  • TELEGRAM_ANTIFLOOD_WINDOW_SECONDS=60 задает общее скользящее окно. Дефолты рассчитаны на нормальные button-heavy флоу: 180 всех апдейтов, 120 сообщений, 240 callback, 60 inline-запросов, 30 команд /start и 60 тяжелых callback за окно.
  • TELEGRAM_ACTION_COOLDOWN_ENABLED=True дедуплицирует точные повторные платежные и trial callback от того же пользователя. Разные платежные payload не объединяются, поэтому обычный checkout остается независимым.
  • Доступ к админке задают роли owner и admin, сохранённые у внутреннего аккаунта.
  • Первый владелец получает роль при входе по заранее заданным BOOTSTRAP_OWNER_TELEGRAM_ID или BOOTSTRAP_OWNER_EMAIL; email должен быть подтверждён. Оба поля необязательны, назначается только один аккаунт. Сохранённое назначение владельца, даже отозванное, блокирует повторную автоматическую выдачу.
  • Без этих полей зарегистрируйте аккаунт и выполните серверную команду docker compose exec backend python backend/scripts/bootstrap_owner.py --minishop-id ms_<id>. Привязка Telegram/email для этой команды не требуется. Подробности: первый владелец.
  • ADMIN_IDS служит только источником одноразового импорта старых администраторов при достоверной привязке Telegram identity.
  • WEBHOOK_BASE_URL должен вести на backend-сервер вебхуков.
  • В Remnawave Panel WEBHOOK_URL должен быть WEBHOOK_BASE_URL + /webhook/panel, например https://app.example.com/webhook/panel.
  • SUBSCRIPTION_MINI_APP_URL должен вести на frontend/Mini App-домен.
  • Не добавляйте /api, /auth или webhook-пути в SUBSCRIPTION_MINI_APP_URL.
  • Браузер пользователя должен ходить только на frontend origin: https://app.example.com/api/....
  • WEBAPP_API_BASE_URL оставляйте /api; отдельный backend origin в frontend JS не является защитой и делает WebApp API напрямую видимым пользователю.
  • Для protected upstream используйте WEBAPP_BACKEND_UPSTREAM у frontend nginx и MINISHOP_EDGE_TOKEN, который nginx добавляет к upstream-запросам server-side.
  • MINISHOP_EDGE_TOKEN нельзя отдавать в runtime config или frontend bundle: browser-visible token виден в DevTools.
  • Token/firewall/VPN применяются к WebApp API plane backend:8081. Telegram, payment provider и Remnawave Panel webhook остаются на public webhook plane backend:8080 и не должны требовать MINISHOP_EDGE_TOKEN.
  • При upstream https://bot.example.com настройте Host/SNI (WEBAPP_BACKEND_UPSTREAM_HOST=bot.example.com) и route order так, чтобы /api/*, /auth/*, /open-app, logo/theme/favicon paths попадали в 8081 раньше generic webhook fallback.
  • Reverse proxy для WEBHOOK_BASE_URL должен передавать X-Forwarded-For с реальным IP отправителя.
  • TRUSTED_PROXIES должен включать IP/CIDR последнего proxy-hop до backend. Иначе платежные webhook-обработчики будут проверять allowlist по IP proxy или Docker gateway.
  • Для домена за Cloudflare backend принимает CF-Connecting-IP, только если ближайший недоверенный hop входит в официальные сети Cloudflare. Добавлять эти публичные CIDR в TRUSTED_PROXIES не требуется.
  • Если TRUSTED_PROXIES не задан, приложение, Compose-профили и установщик доверяют loopback и стандартным сервисам frontend, caddy, nginx, angie, newt, newt-2. Имена host: разрешаются только в отдельные IP, обновляются раз в минуту и игнорируются, пока сервис отсутствует. Это поддерживает несколько прокси и пересоздание контейнеров без ручного изменения адресов.
  • Для собственного proxy добавьте его точный IP/CIDR или host:имя-сервиса к стандартному списку ниже. Установщик добавляет имя выбранного контейнера автоматически; при host-network добавляет точный gateway Docker-сети приложения. Явные настройки оператора сохраняются. При обновлении замените старое доверие всем частным сетям в .env.
  • Если вы сознательно хотите доверять любому proxy-hop, используйте 0.0.0.0/0,::/0, но только когда backend не опубликован напрямую, а внешний proxy очищает входящий X-Forwarded-For.

Для стандартной установки оставьте переменную незаданной. Если нужен дополнительный proxy:

TRUSTED_PROXIES=127.0.0.1,::1,host:frontend,host:caddy,host:nginx,host:angie,host:newt,host:newt-2,host:my-proxy

Список доверенных входящих прокси не разрешает исходящие подключения во внутреннюю сеть. Публичные SMTP, платёжные API и сервисы мониторинга продолжают работать с обычными настройками; внутренние адреса и собственные API-шлюзы разрешаются настройками администратора, как описано ниже.

Исходящие запросы Xray Checker и Uptime Kuma проверяют реальные DNS-адреса и перенаправления. Внутренний сервер мониторинга разрешён по точному имени и порту текущего URL, заданного оператором в .env или сохранённого в админке. Настройкам администратора доверяем по умолчанию: сохранение, замена и сброс URL сразу обновляют разрешения и соединения без перезапуска backend. Старые запросы завершаются с прежними настройками, а новые используют текущий адрес; прежние хосты и порты не остаются разрешёнными. Link-local адреса, включая адреса metadata, не разрешаются.

SMTP также проверяет DNS и подключается к проверенному IP с TLS-проверкой исходного имени. Внутренний SMTP разрешён по текущим явно заданным SMTP_HOST, SMTP_PORT и SMTP_FALLBACK_PORTS из .env или админки. Изменения применяются к следующему подключению без перезапуска; удалённые хосты и порты перестают быть разрешёнными.

URL курсов PayKilla принимает только HTTP(S); синхронный и асинхронный пути ограничивают размер ответа, проверяют DNS и каждое перенаправление. Внутренний сервис курсов можно задать через PAYKILLA_EXCHANGE_RATE_URL в .env или админке. Оба пути используют текущий адрес, а смена URL обновляет разрешения и выбор кэша курса без перезапуска.

Платёжные API отправляют ключи только на текущий адрес <PROVIDER>_BASE_URL, включая его схему и порт. Адрес можно задать в .env или сохранить в админке; сохранённые ранее настройки также учитываются. Изменение в админке применяется без перезапуска, а уже начатые запросы завершаются с прежними настройками. Явно настроенный API-шлюз может использовать частный IP или внутреннее имя. HTTP(S)-адрес проверяется перед сохранением, DNS — при подключении; служебные адреса, включая metadata, запрещены. Перенаправление на другой origin не пересылает ключи, даже если это штатный адрес провайдера.

Отдельный worker обновляет SMTP и настройки платёжных провайдеров из базы каждые 5 секунд, включая сброс к значениям .env. Перезапуск worker для смены адреса не требуется; настройки в процессе backend применяются сразу после сохранения.

Файлы инструкций доступны внутри data/subpage-config или по исходному пути из .env. Чтение ограничено 4 MiB и обычными файлами; административная смена пути не даёт доступ к произвольным файлам сервера.

  • Используйте HTTPS на всех публичных доменах.
  • Ограничивайте доступ к серверу и .env.
  • Следите за логами платежных вебхуков и вебхуков панели.
  • После ротации секретов перезапускайте соответствующие сервисы и проверяйте вебхуки.

См. также переменные окружения и развертывание.