10 KiB
ОТЧЁТ О БЕЗОПАСНОСТИ
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:
- Убрать users count, AIS details, version из публичного health
- Оставить только
{"status":"ok"}для мониторинга - Детальный 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 возвращается на все ответы. Раскрывает:
- Внутренний backend на порту 5050
- Протокол HTTP (не HTTPS) для внутренних запросов
- Dev-конфигурация осталась в production
POC:
curl -sI https://seafare-montana.duckdns.org/
# → Access-Control-Allow-Origin: http://127.0.0.1:5050
Remediation:
- Заменить на
Access-Control-Allow-Origin: https://seafare-montana.duckdns.org - Или динамически проверять 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)
- Убрать детальную информацию из
/health— оставить только{"status":"ok"} - Заменить CORS
127.0.0.1:5050на production домен
В течение недели (Medium)
- Добавить email-верификацию при регистрации
server_tokens offв nginx- Обработать 500 ошибку на subscription/upgrade
- Шифровать payload токена или перейти на JWT
В течение месяца (Low)
- Генерировать wallet-адрес on-demand
- Ограничить /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 Классификация: КОНФИДЕНЦИАЛЬНО