Семь лет я разрабатываю продукты для защиты конечных точек — те самые агенты, которые крутятся у вас в трее и которые принято проклинать, когда билд собирается на десять минут дольше обычного. До этого несколько лет сидел по другую сторону: аналитиком в SOC и в пентестах. Так что жалобы на «тормозящий антивирус» я слышал во всех возможных ролях — и как человек, который эти алерты разбирает, и как человек, который в эти продукты пишет код.
Обычно дискуссия выглядит так: разработчики говорят «EDR сожрал мне полчаса жизни на сборке», безопасники отвечают «терпите, это ради вашей же безопасности», и обе стороны расходятся, оставшись при своём. Я попробую разобрать, что происходит внутри агента на самом деле, где именно теряется производительность и почему часть этих потерь — осознанный выбор, а часть — честный инженерный компромисс, у которого пока нет красивого решения.
Что агент делает при каждом открытии файла
Начнём с самого болезненного — файловых операций.
Когда процесс открывает файл, драйвер агента перехватывает эту операцию до того, как она завершится. В Windows это мини-фильтр файловой системы, в Linux — чаще всего fanotify или eBPF-хуки, в macOS — Endpoint Security Framework. Дальше агент должен ответить на простой вопрос: можно ли этому процессу работать с этим файлом? И ответить быстро, потому что файловая операция стоит и ждёт.
Что происходит в этот момент внутри:
Считается хэш файла (или берётся закэшированный, если файл не менялся).
Хэш пробивается по локальным базам — вердикты, облачные кэши, списки доверенного.
Если файл новый и неизвестный — запускается сканирование: сигнатуры, эвристики, при необходимости эмуляция или запрос в облако.
На одном файле это микросекунды или миллисекунды. Проблема в том, что сборка среднего проекта трогает десятки тысяч файлов: компилятор читает исходники и хедеры, пишет объектники, линкер собирает всё обратно, пакетный менеджер распаковывает зависимости. Каждая операция — потенциальная точка перехвата. Умножьте миллисекунды на десятки тысяч — вот они, ваши минуты.
Казалось бы, решение очевидно: кэшировать агрессивнее. Проверили файл один раз — и не трогаем, пока не изменится. Так все и делают. Но у агрессивного кэширования есть граница, за которой начинается интересное: между моментом проверки файла и моментом его исполнения файл можно подменить. Это классический класс проблем time-of-check to time-of-use (TOCTOU), и для защитного продукта он не теоретический — способы гонок с проверкой известны и описаны. Поэтому в местах, критичных для исполнения кода, агент вынужден перепроверять — и жертвовать скоростью.
Телеметрия: почему агент пишет «вообще всё»
Вторая статья расходов — та, из-за которой EDR и называется EDR, а не антивирусом.
Классический антивирус отвечал на вопрос «этот файл плохой?». Современные атаки на этот вопрос отвечать бесполезно: значительная часть активности выполняется вообще без «плохих файлов» — легитимными системными утилитами, скриптовыми движками, встроенными средствами администрирования. Каждый инструмент по отдельности легален и подписан вендором ОС. Вредоносной является цепочка: кто кого запустил, с какими аргументами, что после этого произошло с сетью и реестром.
Чтобы видеть цепочки, агент должен собирать события: создание процессов, загрузку модулей, сетевые соединения, операции с реестром, инжекты. На нагруженной машине это тысячи событий в секунду. Каждое надо перехватить, нормализовать, прогнать через локальные правила корреляции, часть — отправить на сервер. Это CPU, память и диск — постоянно, фоном, независимо от того, атакуют вас сейчас или нет.
И вот здесь живёт главный компромисс продукта. Можно собирать меньше событий — агент станет легче, а SOC перестанет видеть куски цепочек. В расследовании инцидента дыра в телеметрии означает, что аналитик смотрит на процесс, появившийся «из ниоткуда», и не может сказать, как он туда попал. Можно собирать больше — и получить те самые проценты CPU, за которые нас ругают. Каждый вендор рисует эту границу по-своему, и маркетинг здесь ни при чём: это инженерное решение с измеримой ценой в обе стороны.
Экономика ложных срабатываний
Отдельный источник тормозов, о котором реже говорят: детекты пишутся с запасом.
Представьте, что вы пишете правило детектирования. У вас два способа ошибиться: пропустить атаку (false negative) или сработать на легитимное поведение (false positive). Цена ошибок радикально несимметрична. За пропущенного шифровальщика вендора порвут — клиент, пресса, независимые тесты. За ложное срабатывание… заказчик поворчит и добавит исключение.
Поэтому при прочих равных детект пишется чувствительнее, чем хотелось бы разработчику на эндпоинте. Чувствительный детект — это больше проверок на большем количестве событий, больше промежуточных состояний, которые надо хранить и сопоставлять. Инерция всей индустрии направлена в сторону «лучше перебдеть», и ваш процессор оплачивает эту инерцию.
Я не защищаю такое положение дел, я его объясняю. Изнутри это выглядит как бесконечный тюнинг: каждое правило обрастает уточнениями и исключениями по результатам полевой обкатки, и хороший вендор действительно тратит на это заметную часть ресурсов детект-команды. Но нулевой ложняк при ненулевом детекте — состояние, в которое индустрия не умеет, и врут те, кто обещает обратное.
Что реально можно сделать
Практическая часть — для тех, у кого EDR ест сборку прямо сейчас.
Точечные исключения. Директории сборки, кэши пакетных менеджеров, рабочие каталоги СУБД — легитимные кандидаты на исключение из файлового сканирования. Ключевое слово «точечные»: исключение должно покрывать конкретный путь с конкретным типом нагрузки. «Исключим весь диск D, там всё равно только проекты» — это не оптимизация, это выключение защиты на половине машины, и атакующие про такие исключения прекрасно осведомлены.
Один агент вместо двух. Регулярно встречаю машины, где живут два защитных продукта одновременно — исторически так сложилось. Два драйвера перехватывают одни и те же операции, и в худшем случае каждый сканирует активность другого. Прирост защиты от второго агента — около нуля, прирост тормозов — кратный.
Замерьте, прежде чем ругать. У большинства продуктов есть режимы диагностики производительности, а у ОС — средства профилирования файловых операций. Иногда «EDR тормозит» при замере оказывается антивирусной проверкой в CI-раннере, которую забыли настроить, или сетевым сканированием каждого артефакта при выгрузке. Конкретный замер — это ещё и предметный разговор с вашей ИБ-командой вместо взаимных обвинений.
Поговорите с ИБ до, а не после. Безопасники в большинстве своём не хотят ломать вам сборку — они хотят не пропустить инцидент. Прийти с профилем нагрузки и предложением конкретных исключений работает на порядок лучше, чем тикет «ваш антивирус всё сломал».
Вместо вывода
Вопрос «почему EDR тормозит» на самом деле формулируется иначе: сколько защиты вы готовы обменять на скорость. Агент, который ничего не перехватывает, не тормозит вообще — и не видит ничего. Агент, который проверяет всё синхронно, ловит максимум — и делает машину неюзабельной. Всё, что продаётся на рынке, живёт между этими полюсами, и положение конкретного продукта на этой шкале — следствие сотен маленьких инженерных решений, о которых я попробовал рассказать.
