montana/Русский/Логистика/report_seafare_2026-02-28.md

10 KiB
Raw Permalink Blame History

ОТЧЁТ О БЕЗОПАСНОСТИ

SeaFare Montana (seafare-montana.duckdns.org) — 28.02.2026


Executive Summary

  • Находок: 8 (Критические: 0 | Высокие: 2 | Средние: 4 | Низкие: 2)
  • Общая оценка: Удовлетворительная
  • Критических уязвимостей не найдено. Основные проблемы: утечка внутренней информации через /health, dev-CORS конфиг в production, отсутствие email-верификации. Финансовые endpoints (wallet, subscription) защищены корректно.

Scope

Параметр Значение
Цель https://seafare-montana.duckdns.org
IP 89.19.208.158
Приложение SeaFare Montana — Maritime Logistics AI
Стек nginx/1.24.0 (Ubuntu) → Flask (Python) + PostgreSQL
Интеграции Google OAuth, Telegram Bot, AISStream, Digitraffic, USDT TRC20 (Tron)
Frontend Vanilla HTML/JS + Leaflet.js (карты)
Авторизация Flask itsdangerous signed tokens (Bearer)
Период 28.02.2026
Тип Black-box → Grey-box
Авторизация на тест Подтверждена владельцем

Результаты сканирования портов

Порт Сервис Статус
80 HTTP (nginx) OPEN (→ redirect to HTTPS)
443 HTTPS (nginx) OPEN
22 SSH closed
3306 MySQL closed
5432 PostgreSQL closed
6379 Redis closed
27017 MongoDB closed
5050 Backend (Flask) closed
8080-9200 Все прочие (21 порт) closed

Вердикт: минимальная поверхность атаки. Только HTTP/HTTPS наружу.


API Attack Surface

Открытые эндпоинты (без auth):

Эндпоинт Данные
GET /health Имя сервиса, версия, DB, users count, AIS status
GET /api/v1/auth/config Google OAuth Client ID
GET /api/v1/subscription/plans Планы подписки с ценами
GET /api/v1/ports/search?q= Поиск портов (116K+)
POST /api/v1/auth/register Открытая регистрация
POST /api/v1/auth/login Логин

Авторизированные эндпоинты (21+): auth/me, profile, chat/stream, chat/history, map/vessels, wallet, wallet/check, wallet/withdraw, wallet/withdrawals, subscription/upgrade, purchased-contacts, telegram/status, telegram/link, telegram/unlink, admin/revenue, admin/costs


Находки


[HIGH-001] Health endpoint — массивная утечка внутренней информации

  • Severity: High (CVSS 7.2)
  • Категория: Information Disclosure (OWASP A01:2021)
  • CWE: CWE-200

Описание: Публичный /health раскрывает:

  • Имя сервиса: "SeaFare API" v3.30.0
  • Тип БД: PostgreSQL
  • Количество пользователей: 4 (до теста)
  • AISStream: статус подключения, bounding boxes, reconnect count, thread status
  • Digitraffic: статус конфигурации

POC:

curl -s https://seafare-montana.duckdns.org/health
# → {"db":"ok","db_mode":"postgres","users":4,"version":"3.30.0",
#    "ais":{"aisstream":{"connected":true,"tracked_mmsis":0,...}}}

Impact: Атакующий узнаёт версию, стек, кол-во пользователей, состояние внутренних сервисов без авторизации. Упрощает целевую атаку.

Remediation:

  1. Убрать users count, AIS details, version из публичного health
  2. Оставить только {"status":"ok"} для мониторинга
  3. Детальный health — за авторизацией (admin only)

[HIGH-002] CORS dev-конфиг в production

  • Severity: High (CVSS 6.8)
  • Категория: Security Misconfiguration (OWASP A05:2021)
  • CWE: CWE-942

Описание: Заголовок Access-Control-Allow-Origin: http://127.0.0.1:5050 возвращается на все ответы. Раскрывает:

  1. Внутренний backend на порту 5050
  2. Протокол HTTP (не HTTPS) для внутренних запросов
  3. Dev-конфигурация осталась в production

POC:

curl -sI https://seafare-montana.duckdns.org/
# → Access-Control-Allow-Origin: http://127.0.0.1:5050

Remediation:

  1. Заменить на Access-Control-Allow-Origin: https://seafare-montana.duckdns.org
  2. Или динамически проверять Origin по whitelist

[MED-001] Открытая регистрация без email-верификации

  • Severity: Medium (CVSS 5.3)
  • CWE: CWE-287

Описание: Регистрация мгновенная, без подтверждения email. Аккаунт сразу активен. Можно создавать аккаунты на чужие email.

POC:

curl -s https://seafare-montana.duckdns.org/api/v1/auth/register \
  -X POST -H "Content-Type: application/json" \
  -d '{"email":"anyone@example.com","password":"123456"}'
# → {"success":true, "token":"...", "user":{"id":5,"is_active":true}}

Remediation: Email-верификация перед активацией аккаунта.


[MED-002] nginx версия раскрыта в заголовках

  • Severity: Medium (CVSS 4.3)
  • CWE: CWE-200

Описание: Server: nginx/1.24.0 (Ubuntu) — точная версия и ОС.

Remediation: server_tokens off; в nginx.conf


[MED-003] Flask itsdangerous token — payload в cleartext

  • Severity: Medium (CVSS 4.5)
  • CWE: CWE-311

Описание: Токен аутентификации содержит base64-encoded payload без шифрования. Любой может декодировать:

eyJlbWFpbCI6InBlbnRlc3QuLi4iLCJuYW1lIjoiIn0=
→ {"email":"pentest.seafare@protonmail.com","name":""}

Подпись (HMAC) защищает от модификации, но email виден.

Remediation: Рассмотреть шифрование payload или переход на JWT с минимальным payload (только user_id).


[MED-004] Subscription upgrade — 500 Internal Server Error

  • Severity: Medium (CVSS 4.0)
  • CWE: CWE-209, CWE-755

Описание: POST /api/v1/subscription/upgrade возвращает 500 без обработки ошибки. Может раскрывать stack trace в debug-режиме.

POC:

curl -s https://seafare-montana.duckdns.org/api/v1/subscription/upgrade \
  -X POST -H "Content-Type: application/json" \
  -H "Authorization: Bearer <TOKEN>" \
  -d '{"plan":"pro"}'
# → 500 Internal Server Error

Remediation: Обработать ошибку, вернуть корректный JSON с описанием (недостаточно средств / невалидный план).


[LOW-001] Google OAuth Client ID публично доступен

  • Severity: Low (CVSS 2.5)
  • CWE: CWE-200

Описание: /api/v1/auth/config возвращает Google OAuth Client ID. Сам по себе не секрет (нужен для frontend), но позволяет идентифицировать Google Cloud проект.

{"google_client_id":"199727561298-...apps.googleusercontent.com"}

[LOW-002] Wallet API раскрывает реальный blockchain-адрес

  • Severity: Low (CVSS 3.0)
  • CWE: CWE-200

Описание: /api/v1/wallet возвращает реальный USDT TRC20 адрес: TRyQSvbE43RzZuuDaNSpbTvyxzaKqvTybR. Адрес публично отслеживается на блокчейн-эксплорерах.

Remediation: Генерировать адрес только при запросе на депозит, не показывать постоянно.


Что НЕ уязвимо (хорошие практики)

Проверка Результат
Admin endpoints (revenue, costs) Заблокированы — "Admin access required"
Privilege escalation (is_admin, plan, balance через profile) Заблокировано — поля не меняют auth-модель
Wallet negative amount Заблокировано — min $2 USDT
SQL Injection (ports/search) Не обнаружена — параметризация
CORS reflection (evil origin) Не отражается
Network ports (DB, Redis, SSH) Все закрыты
HSTS Включен — max-age=31536000
Security headers Все присутствуют — XFO, XCT, XXP, RP
TLS Валидный сертификат
Flask SECRET_KEY Не тривиальный — 50 common secrets не подошли
Subscription bypass Не работает — план остался free

Рекомендации по приоритету

Немедленно (High)

  1. Убрать детальную информацию из /health — оставить только {"status":"ok"}
  2. Заменить CORS 127.0.0.1:5050 на production домен

В течение недели (Medium)

  1. Добавить email-верификацию при регистрации
  2. server_tokens off в nginx
  3. Обработать 500 ошибку на subscription/upgrade
  4. Шифровать payload токена или перейти на JWT

В течение месяца (Low)

  1. Генерировать wallet-адрес on-demand
  2. Ограничить /api/v1/auth/config авторизацией

Методология

  • Инструменты: curl, Python 3.14
  • Стандарты: OWASP Top 10 (2021), OWASP API Security Top 10 (2023)
  • Просканировано: 21 порт, 20+ API-эндпоинтов
  • Тестовый аккаунт: pentest.seafare@protonmail.com (ID: 5) — удалить
  • Ущерб: нулевой

Отчёт подготовлен: 28.02.2026 Классификация: КОНФИДЕНЦИАЛЬНО