Обзор — что делает этот экран
Диагностика безопасности запускает на зарегистрированных серверах сканирование следов руткитов и проверку укрепления системы, оценивает каждый результат баллом от 0 до 100 и оценкой от A до F и показывает состояние защищённости всего парка на одном экране. К каждой проверке прилагается пояснение «что / почему / как исправить», а любая находка, которая является провалом с критической серьёзностью (fail + crit), автоматически повышается до обращения в разделе Решение проблем (с устранением дубликатов и автоматическим закрытием, как только проверка снова проходит).
Основные части:
- Зонд
infr_seccheck_probe.cjs— скрипт Node, который выполняется локально и только на чтение на целевом хосте (без учётных данных). Он выполняет 36 проверок и выводит JSON. - Эталонный каталог
App\Support\SecurityCheckbook— владеет 9 категориями, ключами проверок, весами и уровнями серьёзности (не зависит от языка, безопасен для кеша). Пояснительные тексты находятся вresources/lang/{ko,en}/seccheck.php. - Движок
App\Services\Security\DiagnosticsService— приём → подсчёт баллов → повышение и закрытие обращений → агрегация панели. - Хранилище
infr_sec_scan(миграция000766) — одна строка = одно сканирование хоста;findingsхранится встроенно в виде JSON.
Запуск зонда от имени root включает привилегированные проверки, такие как
/etc/shadow,sudoersиsshd -T. Без прав root привилегированные проверки понижаются доskipи исключаются из знаменателя при подсчёте баллов (без штрафа).
Когда это применять
- Проверка базового уровня укрепления перед вводом нового сервера в эксплуатацию.
- Быстрая сортировка следов руткитов и бэкдоров на подозрительном хосте (скрытые процессы, внедрение через
ld.so.preload, сетевая карта в неразборчивом режиме и т. п.). - Регулярный ритм соответствия требованиям — ежедневный запуск зонда по cron, отправляющий баллы через репортёр API, чтобы тренд накапливался автоматически.
- Готовность к аудиту — с одного взгляда видно, на каких хостах работает ОС с истёкшей поддержкой, где не установлены обновления безопасности или разрешён вход по SSH под root.
Устройство экрана
| Область | Содержимое |
|---|---|
| Полоса KPI | Средний балл по парку · количество просканированных хостов · открытые критические обращения · общее число проваленных проверок · время последнего сканирования |
| Распределение оценок | Гистограмма количества хостов с оценками A/B/C/D/F |
| Баллы по категориям | Сводка по 9 категориям (среднее по парку, порядок каталога, цвет тона) |
| Динамика баллов | Последние 60 сканирований в хронологическом порядке |
| Хосты по оценке | Сетка карточек хостов — сначала идут самые низкие (наиболее рискованные) баллы. На каждой карточке показаны оценка, счётчики pass/warn/fail/crit, источник поступления и время сканирования. Щелчок → модальное окно отчёта |
| Модальное окно отчёта | Общий балл и оценка + сводка (ОС/ядро) + подробности по каждой проверке (что/почему/исправление/подтверждение) + ссылка на созданное обращение |
Верхняя панель инструментов: [Запустить сканирование] (удалённый запуск на нескольких серверах) · [Вставить результат] · Обновить · Переключатель автообновления · Полный экран.
Как пользоваться
Четыре пути поступления
infr_sec_scan.source классифицирует, каким образом было получено сканирование:
| source | Точка входа | Способ |
|---|---|---|
emulate |
Окно [Запустить сканирование] | Выберите инстансы → разверните и запустите зонд удалённо. Вставка или применение удалённой эмуляции, несущие instance_id, тоже записываются как emulate |
paste |
Окно [Вставить результат] | Вставьте JSON зонда, полученный непосредственно на цели, без привязки к инстансу |
api |
POST /api/v1/security/scan |
Cron каждого хоста запускает зонд → отправляет данные по ключу API (путь репортёра) |
manual |
Запасной вариант | Значение по умолчанию, когда значение source недопустимо |
1) Удалённый запуск на нескольких серверах — асинхронный опрос
Синхронный полный прогон превысил бы время выполнения PHP на большом числе хостов, поэтому схема такова: регистрация → фоновый обработчик без ожидания → опрос.
- [Запустить сканирование] → отметьте целевые инстансы (у каждого указано, доступен он или недоступен).
POST /security/diagnostics/run→ создаёт запись о ходе выполнения и сразу возвращаетrun_id(Cache, TTL 30 мин).- Фронтенд вызывает
POST /security/diagnostics/run-worker/{runId}не дожидаясь ответа → обработчик последовательно проходит все хосты подset_time_limit(0)иignore_user_abort(сбой одного хоста не останавливает остальные). - Фронтенд опрашивает
GET /security/diagnostics/run-status/{runId}, чтобы обновлять прогресс (done/total/ok).
Инстанс, помеченный как недоступный, не соответствует ни одному узлу коллектора
run_report, поэтому запустить его удалённо нельзя. Запустите зонд прямо на хосте и отправьте результат через [Вставить результат]. Об организации удалённого запуска см. Удалённую эмуляцию.
2) Вставка / приём JSON
Запустите зонд на целевом хосте и вставьте его JSON.
# На целевом хосте (рекомендуется: root)
node infr_seccheck_probe.cjs --min
--min выводит JSON одной строкой. Форма вывода:
{
"host": "web-01",
"generated_at": "2026-08-13T03:30:00Z",
"os": "Rocky Linux 9.3",
"kernel": "5.14.0-362.el9",
"root": true,
"checks": [
{ "key": "ssh_root_login", "category": "ssh", "status": "fail", "severity": "crit", "detail": "PermitRootLogin yes", "evidence": "/etc/ssh/sshd_config:32" },
{ "key": "svc_firewall", "category": "services", "status": "pass", "severity": "crit", "detail": "firewalld active" }
],
"summary": {}
}
Приём выполняет POST /security/diagnostics/ingest. Привязка к инстансу записывается как source=emulate; если привязки нет, записывается source=paste.
3) Репортёр API (автоматизация)
Cron каждого хоста запускает зонд и отправляет результат в InfraGuard. Ключ API выпускается в разделе Администрирование ▸ API-ключи; ключ должен иметь область действия scan.write.
30 3 * * * node /opt/infr/infr_seccheck_probe.cjs --min | curl -sS -X POST https://infraguard.example.com/api/v1/security/scan -H "Authorization: Bearer YOUR_API_KEY" -H "Content-Type: application/json" --data @-
Ответ (201):
{ "ok": true, "scan_id": 812, "host": "web-01", "score": 74, "grade": "C" }
Подсчёт баллов — SecurityCheckbook
Балл — это взвешенное отношение, построенное на весе и статусе каждой проверки.
Коэффициент статуса (STATUS_FACTOR) — учитываются только эти значения; skip/info исключаются из знаменателя:
| Статус | Коэффициент |
|---|---|
pass |
1.0 |
warn |
0.6 |
fail |
0.0 |
skip · info |
исключены |
Множитель серьёзности (SEV_MUL) — чем тяжелее последствия провала, тем сильнее он сдвигает балл:
| fail_severity | Множитель |
|---|---|
crit |
1.6 |
warn |
1.0 |
info |
0.5 |
Вес отдельной проверки w = check_weight(1–3) × severity_multiplier; итоговый балл = round(100 × Σ(w × status_factor) / Σw). Баллы по категориям считаются по той же формуле в пределах каждой категории.
Оценка и тон:
| Балл | Оценка | Тон |
|---|---|---|
| ≥ 90 | A | good |
| ≥ 80 | B | good |
| ≥ 70 | C | warn |
| ≥ 60 | D | warn |
| < 60 | F | crit |
(Оценки — A/B/C/D/F; тон: good ≥ 80 · warn ≥ 60 · crit < 60.)
9 категорий · 36 проверок
У каждой категории есть отображаемый вес и значок; фактический подсчёт использует описанный выше вес проверки × множитель серьёзности.
| Категория | Название | Проверок | Заметные проверки (что означает провал) |
|---|---|---|---|
rootkit |
Руткиты / вредоносное ПО | 6 | rk_known_files·rk_ld_preload·rk_hidden_proc (crit) |
patch |
Патчи / обновления | 3 | pt_security_updates·pt_eol_os (crit) |
ssh |
Настройка SSH | 5 | ssh_root_login·ssh_empty_pass (crit) |
accounts |
Учётные записи / привилегии | 5 | acc_uid0·acc_empty_pass (crit) |
network |
Сетевая доступность извне | 3 | net_legacy_services·net_db_exposed (crit) |
filesystem |
Права файловой системы | 5 | fs_shadow_perm (crit)·fs_world_writable·fs_suid (warn) |
hardening |
Укрепление системы | 5 | hd_selinux·hd_aslr·hd_syncookies (warn) |
services |
Службы / межсетевой экран | 2 | svc_firewall (crit)·svc_unnecessary (info) |
logging |
Аудит / журналирование | 2 | log_auditd·log_syslog (warn) |
Неизвестные ключи поглощаются категорией other. Текст «что / почему / исправление» для каждой проверки отображается в модальном окне отчёта из seccheck.check.*.
Критические находки → повышение до решения проблем
При каждом приёме reconcileCases() сверяет обращения по этому хосту.
- Повышаются только находки со
status = failИseverity = crit. Ключ устранения дубликатов — внутреннийfingerprint. - Если открытое обращение уже есть, увеличивается
occurrence_count++и обновляетсяlast_occurred_at; иначе создаётся новое обращение:infr_incident(area=security,source=detection,entity_type=seccheck,entity_key=host,severity=crit,status=open) плюс записьinfr_incident_event(kind=created). - Автоматическое закрытие: ранее открытое обращение, которое в текущем сканировании больше не является fail+crit (исправлено или не обнаружено), переводится в
status=resolvedс заполнениемresolved_atи примечанием об автоматическом закрытии.
Повышенные проверки отображаются в модальном окне отчёта со значком «повышено до обращения» и ссылкой [Открыть обращение]. С обращениями работают на доске Безопасность ▸ Решение проблем.
Удаление сканирования (
POST /security/diagnostics/delete) не удаляет созданные по нему обращения — они независимы.
Источники данных
| Источник | Роль |
|---|---|
infr_sec_scan (000766) |
Результаты сканирований (по одному на хост). JSON с score·grade·pass/warn/fail/crit/total_count·category_scores·summary·findings. Индексы (host,scanned_at)·(instance_id,scanned_at)·grade·score |
infr_instance |
Целевые инстансы (сопоставляет host → instance_id по alias/hostname) |
infr_incident / infr_incident_event |
Созданные критические обращения и их хронология |
infr_api_key |
Аутентификация репортёра API (область действия scan.write) |
| Cache | Агрегат панели кешируется на 20 с (infr:sec:diag:build) · запись о ходе асинхронного запуска (TTL 1800 с) |
infr_seccheck_probe.cjs |
Исходный зонд (локальный, только на чтение) |
- Дисциплина агрегации: среди 500 последних сканирований оставляем только самое свежее по каждому хосту (устранение дубликатов) → список парка, среднее, сводка по категориям, динамика, количество открытых критических обращений.
- Категория и серьёзность, присланные зондом, — лишь подсказки; сервер приводит их к эталонным значениям через
SecurityCheckbook.
Права доступа
- Чтение: требуется доступ к ролевой области «Безопасность» (в текущей градации staff = 5 / admin = 10; demo = 1 область безопасности не видит). Позволяет просматривать панель и отчёты.
- Запись (запуск / приём / удаление): требуется
infr_user_level >= 2в сессии (canWrite()). Ниже этого уровняrun·ingest·deleteвозвращают 403 (seccheck.toast.forbidden). - Репортёр API: промежуточный слой
infr.apikeyплюс ключ с областью действияscan.write; иначе 403forbidden_scope. - Аудит: каждая запись фиксируется в
infr_audit_log—sec.diag_run(количество целей),sec.diag_ingest(scan_id·score·source),sec.diag_delete(id сканирования). Проверить это можно в Журнале аудита.
Об уровневой модели в целом (промежуточный слой infr.level:N) см. Уровни RBAC.
Устранение неполадок и частые вопросы
Q. В окне [Запустить сканирование] инстанс отмечен как «недоступный».
Он не соответствует ни одному узлу коллектора run_report, поэтому механизма удалённого запуска для него нет. Запустите зонд прямо на хосте и отправьте результат через [Вставить результат].
Q. Ошибка «No checks found».
Во вставленном JSON нет массива checks (или items), либо у элементов отсутствует key. Вставьте вывод infr_seccheck_probe.cjs --min дословно.
Q. Балл низкий, хотя провалов немного.
Дело в множителе серьёзности. Один провал crit весит в 1,6 раза больше, чем warn. Посмотрите баллы по категориям и модальное окно отчёта, чтобы понять, какая находка тянет балл вниз.
Q. Все привилегированные проверки в состоянии skip.
Зонд был запущен под учётной записью без прав root. Проверкам вроде /etc/shadow, sudoers и sshd -T нужен root. skip исключается из знаменателя (без штрафа), но для полной диагностики запускайте зонд от root (или через шлюз).
Q. Запуск занимает время — можно закрыть браузер?
Да. Обработчик запускается без ожидания и продолжает работу под ignore_user_abort, даже если запрос прерван. Откройте страницу снова и опрашивайте run-status либо просто посмотрите оценки, когда они появятся на панели. Запись о ходе выполнения хранится 30 минут.
Q. Обращение исчезло само собой. Если последующее сканирование больше не сообщает об этой находке как о fail+crit (исправлено или не обнаружено), движок закрывает обращение автоматически. Это штатное поведение.
Смежные материалы
- Безопасность ▸ Решение проблем — рабочий процесс по повышенным критическим обращениям
- Удалённая эмуляция — развёртывание зонда и организация запуска на нескольких серверах
- API-ключи — ключи для пути репортёра (область действия
scan.write) - Активы ▸ Инстансы — реестр целевых экземпляров операционных систем
- Безопасность ▸ Обзор — полное описание воронки защиты
- Журнал аудита — история запусков / приёмов / удалений
