Перейти к содержанию

Обоснование надёжности

На этой странице доказывается, что DumbMonit отвечает своим требованиям безопасности: перечислены угрозы, границы, на которых меняется доверие, причины, по которым устройство системы ограничивает последствия ошибки, способы противодействия каждому распространённому классу уязвимостей и подтверждения для каждого утверждения. Она дополняет модель безопасности, где те же меры перечислены короче. Чтобы сообщить об уязвимости, следуйте политике безопасности.

Пути к файлам ниже указаны относительно корня репозитория.

Требования безопасности

  1. Читать или изменять конфигурацию, оповещения и измерения может только аутентифицированный пользователь, чья роль это разрешает.
  2. Учётные данные, которые DumbMonit хранит для ваших мониторов, нельзя прочитать ни из файла базы данных, ни из резервной копии без парольной фразы, ни через API.
  3. Передавать измерения может только машина с действительным токеном, а утёкший токен можно отозвать отдельно.
  4. DumbMonit нельзя превратить в средство доступа к сервисам, к которым доступа быть не должно, в частности к собственному дочернему процессу VictoriaMetrics без аутентификации.
  5. Страница, отданная браузеру, не может выполнить скрипт, которого она с собой не поставляла, а сторонний сайт не может заставить вошедший в систему браузер что-либо изменить.

Модель угроз

Злоумышленник Возможности В рамках модели
Анонимный сетевой клиент Достигает HTTP-порта Да
Вошедший пользователь с низкой ролью Действительный сеанс или токен API только для чтения Да (повышение привилегий)
Вредоносная веб-страница Работает в браузере администратора Да (CSRF, XSS, clickjacking)
Скомпрометированный или вредоносный отслеживаемый монитор Отвечает на опросы враждебным содержимым Да (парсеры, перенаправления)
Вредоносный или украденный агент Владеет одним токеном агента Да (область действия одного токена)
Администратор, вводящий враждебный URL Настраивает вебхук или адрес монитора Да, для собственных адресов сервера
Тот, кто контролирует хост, том /data или среду выполнения контейнеров Полный контроль Нет: вне модели, как и в политике безопасности
Уязвимости внутри VictoriaMetrics или отслеживаемых мониторов Сторонний код Нет: сообщайте разработчикам upstream

Границы доверия

Граница Что её пересекает Как защищена Подтверждения
Браузер — /api/* Сеансовый cookie или токен API, JSON Один слой аутентификации, три роли, заголовок CSRF для записи с аутентификацией по cookie crates/server/src/auth/middleware.rs; тесты auth_api.rs, operator_role_api.rs, api_open_security_api.rs, cors_policy_api.rs
Браузер — отдаваемые страницы HTML, скрипты, стили Content Security Policy с nonce для каждого ответа, nosniff, Referrer-Policy: same-origin, X-Frame-Options: DENY crates/server/src/api/mod.rs (слой заголовков безопасности)
Провайдер идентификации — сервер Перенаправление OpenID Connect и ID-токен State, nonce и PKCE (S256); привязка локальной учётной записи выполняется явно crates/server/src/auth/oidc/; тест oidc_api.rs
Агент — /api/ingest Измерения, результаты команд Токен каждого агента, хранится как хеш SHA-256 (префикс dmon_) crates/server/src/api/ingest.rs, crates/server/src/collectors/agent/token.rs; тест agent_binding_api.rs
Агент-ретранслятор — сервер Результаты опросов из другой сети Та же проверка токена агента (agent_commands::authenticate) crates/server/src/api/relay.rs; тест relay_api.rs
Сервер — отслеживаемые мониторы Запросы опроса, враждебные ответы Перенаправления только в пределах того же хоста, ограниченное число перенаправлений, парсеры ответов с модульными тестами, проверка сертификатов включена по умолчанию crates/collectors/src/http.rs (same_host_redirects)
Сервер — каналы уведомлений Запросы вебхуков и SMTP Та же политика перенаправлений плюс защита, отклоняющая собственные адреса сервера; проверка выполняется перед отправкой, при каждом перенаправлении и при разрешении DNS crates/server/src/notify/guard.rs; тест notify_guard_api.rs
Сервер — VictoriaMetrics Записи и запросы на чтение Встроенный дочерний процесс по умолчанию слушает 127.0.0.1:8428; Prometheus-совместимый прокси пропускает только маршруты чтения (query, query_range, series, labels) crates/server/src/config.rs (DUMBMONIT_VM_LISTEN), crates/server/src/api/prometheus.rs (readable_segments)
Сервер — SQLite Конфигурация и состояние Привязанные параметры через sqlx crates/server/src/db/
Сервер — /data База данных, секретный ключ Секреты шифруются AES-256-GCM; пользователь контейнера владеет только /data crates/server/src/crypto.rs, Dockerfile

Аргументация безопасного проектирования

Аргументация следует принципам проектирования Зальцера и Шрёдера.

  • Экономичность механизма. Один бинарный файл, один файл SQLite, один дочерний процесс на loopback, один вход для всех клиентов (/api/*).
  • Безопасные значения по умолчанию. На свежем экземпляре каждый маршрут под защитой аутентификации отвечает 401; отвечают только health, статус аутентификации, setup и login, поэтому никто не может подготовить экземпляр раньше его владельца (auth/middleware.rs, тест api_open_security_api.rs). VictoriaMetrics слушает loopback, пока оператор не изменит это. Сертификаты TLS наблюдаемых сервисов проверяются, если оператор не задал insecure_tls (crates/collectors/src/http.rs).
  • Полное посредничество. Слой аутентификации работает на каждом маршруте API, а не оставляет проверку каждому обработчику.
  • Открытое проектирование. Код, описание API (crates/server/src/api/openapi.yaml) и эта страница общедоступны. Безопасность не зависит от секретности устройства системы.
  • Разделение привилегий. Сеансы, токены API и токены агентов — разные учётные данные. Токены API имеют область read или write (auth/token.rs), а у пользователей роль наблюдателя, оператора или администратора.
  • Наименьшие привилегии. Образ работает с UID 65532 (Dockerfile). Запущенный от root (user: "0:0", для bind mount), сервер лишь передаёт каталог данных этому пользователю, не переходя по ссылкам, затем навсегда отказывается от root и проверяет, что вернуть его нельзя, прежде чем открывать что-либо ещё (privileges.rs). Файл Compose оставляет только четыре capabilities, нужные этому шагу, делает корневую файловую систему доступной только для чтения и задаёт no-new- privileges (docker-compose.yml).
  • Наименьший общий механизм. Агенты аутентифицируются собственным токеном, поэтому отзыв одной машины не затрагивает ни пользователей, ни других агентов.
  • Психологическая приемлемость. Безопасное поведение включено по умолчанию и не требует лишних шагов: cookie имеет флаги HttpOnly и SameSite=Lax, заголовок CSRF добавляется веб-клиентом, секреты в интерфейсе доступны только для записи.
  • Эшелонированная защита. Шифрование при хранении поверх контроля доступа; заголовок CSRF поверх SameSite; ограничение частоты входа поверх хеширования Argon2; политика перенаправлений поверх защиты от собственных адресов.

Криптография

  • Пароли: Argon2 (auth/password.rs). Секреты сеансов и токенов API хранятся в виде хешей SHA-256 от случайных значений (auth/session.rs, auth/token.rs).
  • Секреты при хранении: AES-256-GCM со свежим nonce при каждом шифровании (crypto.rs). Ключ получается с помощью Argon2id из DUMBMONIT_SECRET или сгенерированного файла ключа с постоянной солью; секрет короче 16 символов отклоняется, а контрольное значение при запуске выявляет неверный ключ.
  • Резервные копии: ключ выводится из парольной фразы оператора с помощью Argon2id, параметры хранятся в самом архиве, поэтому алгоритм можно менять, не ломая старые архивы (backup/bundle.rs).
  • Второй фактор: TOTP с хешированными одноразовыми резервными кодами (auth/totp.rs).
  • OpenID Connect: state, nonce и PKCE S256 (auth/oidc/pkce.rs).
  • Все примитивы взяты из поддерживаемых библиотек (aes-gcm, argon2, sha2); ничего самодельного. Встроенный обработчик принимает только HTTPS (обычный HTTP-запрос получает перенаправление), а cookie получает флаг Secure (auth/cookie.rs).

Меры противодействия распространённым уязвимостям

Уязвимость (OWASP Top 10, CWE) Мера противодействия Подтверждения
Нарушенный контроль доступа, CWE-862, CWE-285 Слой аутентификации, роли, области токенов operator_role_api.rs, api_tokens_api.rs, api_open_security_api.rs
Криптографические сбои, CWE-327, CWE-312 AES-256-GCM при хранении, Argon2, API не возвращает секреты модульные тесты crypto.rs; has_secret / credential_kind вместо секрета
SQL-инъекция, CWE-89 Привязанные параметры через sqlx crates/server/src/db/
Межсайтовый скриптинг, CWE-79 Svelte экранирует вывод; CSP с default-src 'none', скрипты только из 'self' и с nonce; base-uri 'none' api/mod.rs
Межсайтовая подделка запросов, CWE-352 Запись через cookie требует X-Requested-With: DumbMonit или метаданные fetch того же источника; CORS не разрешает этот заголовок никому; SameSite=Lax auth/middleware.rs, auth/cors.rs; тест cors_policy_api.rs
Clickjacking, CWE-1021 X-Frame-Options: DENY и frame-ancestors 'none', кроме публичных страниц статуса, которые включены явно и предназначены для встраивания api/mod.rs
Подделка запросов со стороны сервера, CWE-918 Перенаправления только в пределах того же хоста; защита уведомлений отклоняет собственные адреса сервера и VictoriaMetrics, в том числе после разрешения DNS (rebinding). Loopback и частные диапазоны намеренно остаются доступными, потому что там живут сервисы домашней лаборатории notify/guard.rs; тест notify_guard_api.rs
Сбои аутентификации, CWE-307, CWE-287 Ограничение частоты входа с растущей задержкой по адресу и по учётной записи, необязательный TOTP, OIDC с PKCE, сброс второго фактора администратором auth/rate_limit.rs, auth/totp.rs, auth/oidc/
Небезопасная десериализация, исчерпание ресурсов, CWE-400 Типизированный JSON через serde, тела запросов ограничены 16 МиБ, число перенаправлений ограничено api/mod.rs, collectors/src/http.rs
Безопасность памяти, CWE-787, CWE-416 Rust; unsafe встречается только в коде счётчиков производительности агента для Windows (crates/agent/src/collect/perf_counters.rs) поиск unsafe через grep
Уязвимые компоненты, CWE-1104 cargo deny (лицензии, запреты, рекомендации); Dependabot; сканирование опубликованных образов Trivy; actions закреплены по коммиту; сборки с --locked .github/workflows/ci.yml, security.yml, .github/dependabot.yml, deny.toml
Целостность программ и данных, CWE-494 Установщики агента проверяют SHA-256 загруженного бинарного файла crates/agent/install/install.sh, install.ps1
Сбои журналирования и мониторинга, CWE-778 Журнал безопасности входов и важных изменений auth/audit.rs; тест security_audit_api.rs

Известные остаточные риски перечислены в модели безопасности (самоподписанный сертификат по умолчанию, незашифрованные параметры мониторов, встроенная VictoriaMetrics без аутентификации). CSP допускает встроенные стили (style-src 'unsafe-inline'), что ослабляет защиту от внедрения стилей, но не от выполнения скриптов. Существует одна принятая рекомендация, RUSTSEC-2023-0071, которая игнорируется в deny.toml с указанием причины: крейт rsa проверяет подписи RS256 открытым ключом провайдера и никогда не использует закрытый ключ.

Подтверждения

  • Непрерывная интеграция (.github/workflows/ci.yml): cargo fmt --check, clippy -D warnings, полный набор тестов Rust, cargo deny check licenses bans и cargo deny check advisories, проверка типов веб-части, веб-тесты и сборка, а также сборка образа Docker при каждом push и pull request.
  • Сканирование по расписанию (.github/workflows/security.yml): Trivy для опубликованных образов сервера и агента и OpenSSF Scorecard — еженедельно и после каждой публикации :edge. Результаты отображаются на вкладке Security репозитория, куда также поступают отчёты GitHub code scanning (CodeQL).
  • Тесты: тесты API, аутентификации, ролей, CORS, OIDC, защиты и аудита в crates/server/tests/, модульные тесты рядом с кодом и веб-тесты в web/tests/. Покрытие строк Rust, измеренное с помощью cargo-llvm-cov, составляет 91 %.
  • Политика регрессий: исправление сопровождается тестом, который без него не проходит (см. политику тестирования в CONTRIBUTING.md).
  • Публичная запись: исправления безопасности публикуются как advisories и перечисляются в примечаниях к релизу.