Деревья атак и поверхность атаки

Учимся раскладывать «как сюда вообще можно прорваться» на дерево конкретных путей — и сознательно убирать лишние двери, пока их не нашли за нас.

Дерево атаки (attack tree) — иерархическая модель, где корень это цель злоумышленника, а ветви — альтернативные и составные способы её достичь; листья отвечают конкретным уязвимостям и шагам.

STRIDE отвечает на вопрос «какие угрозы возможны», а дерево атак — на вопрос «какими путями цель реально достижима и какой из путей самый дешёвый для атакующего». Это инструмент мышления: вы ставите себя на место нарушителя, формулируете его цель и честно перечисляете способы её добиться. Рядом живёт второе ключевое понятие — поверхность атаки: совокупность всех точек, через которые в систему можно «постучаться». Чем она меньше, тем меньше у дерева атак листьев. Поэтому два навыка работают в паре: деревом атак мы видим пути, минимизацией поверхности — отрезаем их у основания.

Зачем это знать защитнику

Защитнику дерево атак показывает, где тратить усилия. Если к цели ведут пять путей, а вы укрепили один, злоумышленник пойдёт по оставшимся четырём — безопасность системы определяется самым слабым путём, а не самым сильным. Дерево заставляет смотреть на систему целиком и сравнивать пути по стоимости: какой требует меньше навыков, времени и доступа. А карта поверхности атаки превращается в практический чек-лист: каждый открытый порт, эндпоинт, форма загрузки файла, сторонняя интеграция — это вход, который нужно либо защитить, либо убрать. Рисовать деревья атак для своей системы законно и полезно; это проектная дисциплина, а не подготовка взлома.

Как устроено дерево атак

В корне — цель, например «получить доступ к данным пользователей». Ниже — узлы-способы, соединённые логикой ИЛИ (достаточно любого) или И (нужны все сразу). Листья — атомарные действия. Текстом дерево записывают отступами:

ЦЕЛЬ: получить доступ к данным пользователей
├── ИЛИ: украсть учётные данные
│   ├── фишинг сотрудника
│   └── подбор слабого пароля
├── ИЛИ: использовать уязвимость приложения
│   ├── инъекция в недоверенный ввод
│   └── обойти проверку доступа (broken access control)
└── И: получить доступ к бэкапу
    ├── найти открытое хранилище бэкапов
    └── И бэкап не зашифрован

Ветка «бэкап» — пример узла И: данные утекут, только если хранилище доступно и бэкап не зашифрован. Это сразу подсказывает дешёвую защиту: достаточно закрыть любое из двух условий (зашифровать бэкап), и вся ветка обрывается. Узлы можно помечать оценками — стоимость для атакующего, нужные навыки, шанс обнаружения — и так находить самый вероятный путь, чтобы укреплять именно его.

Поверхность атаки и доверительные границы

Поверхность атаки — это все точки взаимодействия с внешним миром: сетевые порты и эндпоинты API, формы и параметры, загрузка файлов, переменные окружения, сторонние библиотеки и сервисы, интерфейсы администратора. Каждая такая точка — потенциальный лист дерева атак. Базовое правило: чем меньше поверхность, тем меньше путей внутрь. Отсюда — практики минимизации: отключать неиспользуемые эндпоинты и порты, не публиковать админку в открытый интернет, удалять мёртвый код и лишние зависимости, держать дефолтную конфигурацию закрытой.

Доверительные границы (trust boundaries) делят систему на зоны с разным уровнем доверия: интернет, DMZ, внутренняя сеть, БД. Данные, пересекающие границу в сторону большего доверия, обязаны проходить проверку — здесь происходит большинство атак. Хорошая архитектура делает границы явными и немногочисленными и валидирует всё, что их пересекает.

Как это работает под капотом

Минимизация поверхности — это во многом про конфигурацию по умолчанию. Сервис, который при старте открывает наружу отладочный или административный интерфейс, добавляет в дерево атак готовый лист. Сравните намерение:

# УЯЗВИМАЯ конфигурация: админ-панель и отладка открыты всему интернету.
# Это два «бесплатных» листа в дереве атак.
bind_address: 0.0.0.0      # слушаем на всех интерфейсах, включая внешний
admin_panel:  enabled      # доступна без ограничения по сети
debug_mode:   true         # отдаёт стек-трейсы и внутренние пути
# БЕЗОПАСНАЯ конфигурация: поверхность сведена к минимуму.
bind_address: 127.0.0.1    # доступ только из внутренней сети/через VPN
admin_panel:  internal_only
debug_mode:   false        # наружу — нейтральные сообщения об ошибках

Каждая убранная точка входа — это ветка дерева атак, которой больше нет. Поэтому минимизацию поверхности удобно вести именно по дереву: построили дерево, нашли листья, спросили по каждому «можно ли вообще убрать эту дверь, а не только повесить замок».

Как защититься

Стройте дерево атак для ключевых целей и укрепляйте самые дешёвые для атакующего пути, а не только очевидные. Сводите поверхность атаки к минимуму: отключайте неиспользуемое, не выставляйте админ-интерфейсы наружу, убирайте лишние зависимости и дефолтные учётки. Делайте доверительные границы явными и валидируйте всё, что их пересекает. Используйте узлы И в свою пользу: если для успеха атаки нужны два условия, достаточно гарантированно убрать одно (например, всегда шифровать бэкапы) — и целая ветка становится недостижимой. Помните юридическую рамку: моделировать и тестировать так можно только свои системы или системы с письменного согласия владельца (ст. 272 УК РФ).

Итоги

  • Дерево атак раскладывает цель злоумышленника на конкретные пути; узлы — ИЛИ (любой) и И (все сразу).
  • Безопасность определяется самым слабым путём — укреплять надо все ведущие к цели ветки.
  • Поверхность атаки — все точки входа; чем она меньше, тем меньше путей у атакующего.
  • Минимизация поверхности: отключать неиспользуемое, прятать админку, убирать лишние зависимости и дефолтные настройки.
  • Узел «И» — подарок защитнику: убрав одно из условий, обрываешь всю ветку (например, шифрование бэкапа).
Проверьте себя
1. Чем отличается узел «И» от узла «ИЛИ» в дереве атак?
A«И» означает, что атака невозможна, а «ИЛИ» — что возможна
BДля узла «ИЛИ» достаточно любого из дочерних путей, а для узла «И» нужны все дочерние условия одновременно
C«И» относится к защите, «ИЛИ» — к нападению
DРазницы нет, это синонимы
2. Почему уменьшение поверхности атаки — эффективная стратегия защиты?
AОно ускоряет работу приложения
BКаждая точка входа (порт, эндпоинт, форма, зависимость) — потенциальный путь атаки; убирая лишние точки, мы удаляем целые ветки дерева атак, а не просто вешаем на них замки
CОно уменьшает размер исходного кода для компиляции
DОно делает логи короче