О чем материал
Рассказываем об AI-сервисе, который автоматизирует процесс подготовки экспертного контента в SIEM.
Скорость подготовки экспертного контента, в том числе правил нормализации данных, напрямую влияет на эффективность SIEM-систем. В крупных инфраструктурах задействовано огромное число ПО, поэтому для ручной обработки информации требуются десятки экспертов. Автоматизация этого процесса с помощью AI-ассистента позволяет сократить трудозатраты и обеспечить быструю генерацию новых правил в заданном формате.
Кластеризация журнала источника
Для начала нам нужно сгруппировать сообщения из логов источника по схожим признакам. Это поможет сократить число уникальных обработчиков, упростить процесс нормализации и повысить эффективность всей системы. В качестве примера рассмотрим вымышленный лог от межсетевого экрана.
Группа 1: Сетевые атаки
Событие 1: [2024-08-23 10:05:15] [Network] [Alert] msgid: NET-001. Suspicious outbound traffic detected. Source IP: 192.168.1.10. Destination IP: 203.0.113.45. Protocol: TCP. Port: 443. Data Volume: 50 MB. Source: Firewall.
Событие 2: [2024-08-23 10:33:10] [Network] [Alert] msgid: NET-001. Suspicious outbound traffic detected. Source IP: 192.168.1.20. Destination IP: 203.0.113.55. Protocol: TCP. Port: 443. Data Volume: 60 MB. Source: Firewall.
Группа 2: Попытки несанкционированного доступа
Событие 1: [2024-08-23 09:45:30] [Authentication] [Alert] msgid: AUTH-002. Failed login attempt detected. Username: 'ivanov'. Source IP: 198.51.100.25. Result: Incorrect password. Source: Authentication Server.
Событие 2: [2024-08-23 10:15:47] [Authentication] [Alert] msgid: AUTH-002. Failed login attempt detected. Username: 'sidorov'. Source IP: 198.51.100.30. Result: Incorrect password. Source: Authentication Server.
Здесь представлены две группы сообщений: одна связана с сетевыми атаками, другая — с попытками несанкционированного доступа. Однако в журнале, который попадет в SIEM-систему, все они будут перемешаны. Более того, в реальных сценариях подобных групп сообщений будет гораздо больше, поэтому для эффективной работы с источником нужна кластеризация. Поскольку документация к источникам обычно не содержит информации о типах и структуре генерируемых событий, мы обратимся к методам машинного обучения.
Итак, кластеризация сообщений от источника проходит в два этапа: первый — группировка сообщений по идентификатору события, второй — текстовая обработка и применение алгоритмов кластеризации.
Вернемся к нашему примеру и обратим внимание на поле msgid.
Группа 1: Сетевые атаки
Событие 1: [2024-08-23 10:05:15] [Network] [Alert] msgid: NET-001. Suspicious outbound traffic detected. Source IP: 192.168.1.10. Destination IP: 203.0.113.45. Protocol: TCP. Port: 443. Data Volume: 50 MB. Source: Firewall.
Группа 2: Попытки несанкционированного доступа
Событие 1: [2024-08-23 09:45:30] [Authentication] [Alert] msgid: AUTH-002. Failed login attempt detected. Username: 'ivanov'. Source IP: 198.51.100.25. Result: Incorrect password. Source: Authentication Server.
Если бы это поле записывалось в таком виде во всех событиях, мы бы извлекли его с помощью простого регулярного выражения и выполнили группировку по словам. Но в реальности поле msgid может и вовсе отсутствовать... К счастью, большие языковые модели настолько круты, что могут извлекать msgid, проанализировав сообщение.
Однако этот подход нельзя назвать киллер-решением, поскольку поле msgid присутствует лишь в 70% событий. В остальных случаях модель выдает NOT_FIELD: для таких событий будет выполняться классический NLP-пайплайн, включающий токенизацию, векторизацию и кластеризацию.
Отмечу, что сообщения в журналах содержат множество динамических данных, которые будут влиять на эффективность кластеризации. Это IP-адреса, время, хосты, пути к файлам, ссылки на веб-ресурсы и т. д. Важно провести препроцессинг и очистить сообщения от подобных элементов, чтобы сократить вариативность данных и сконцентрироваться на ключевых деталях (текстовых описаниях и идентификаторах событий).
Препроцессинг состоит из множества этапов — от составления списка регулярных выражений и удаления мусорных токенов до лемматизации очищенных строк. На выходе получаем набор ключевых токенов, по которым производится разбиение на кластеры. Затем вычисляется матрица расстояний (с помощью расстояния Индела).
Алгоритм K-means не подходит для решения этой задачи, поскольку требует заданного количества кластеров и плохо реагирует на шум и выбросы. К тому же в логах источников могут встречаться события с разной структурой и частотой появления, поэтому важно иметь возможность обнаруживать кластеры с разной плотностью и формой. Исходя из этого, мы выбрали HDBScan — плотностный алгоритм кластеризации, который способен выделять группы сообщений без фиксированного числа кластеров, а также игнорировать редкие или нерегулярные события.
Рассмотрим результат двух этапов кластеризации на новом журнале от источника. Мы отобразили полученные данные на плоскости с помощью метода уменьшения размерности t-SNE (см. рис. 3). Видим 25 кластеров при верном разбиении на 26 кластеров — один из них объединил две группы событий, поскольку информативные токены в них отличаются лишь частицей отрицания NOT.
Генерирование форматной строки
Теперь нужно сгенерировать правила нормализации для каждой из полученных групп сообщений. Для этого мы будем использовать разработанный в Позитиве язык eXtraction and Processing (XP).
Если сильно упростить, правило нормализации — это парсер на стероидах. Он должен описывать поведение ключевых данных в сообщении и на языке XP заполнять поля нормализации, которые далее попадут в SIEM. В начале каждого правила пишется форматная строка. Это некоторое «регулярное выражение» для строки сообщения, в которой:
- токенизированы изменяющиеся значения;
- расставлены поля по схеме SIEM;
- учтено положение слов и знаки пунктуации;
- выделены ключевые переменные, к которым можно обратиться при написании кода на языке XP.
К слову, это общая задача для всех систем сбора и анализа логов. Обычно она решается путем выделения именованных сущностей (named entity recognition), ведь в первую очередь важно определить, к чему относится выделенная подстрока: домен, ip-адрес, токен и т. д. В нашем же случае необходимо еще написать код на языке XP, зная схему полей SIEM из документации. Поэтому мы решили использовать seq2seq-модели, переводящие строки из сырого формата в нормализованный.
Мы остановились на семействе моделей flan-t5 от Google, которые решают seq2seq-задачи на естественном языке. Их архитектура включает энкодер (как BERT) для понимания текста из входных данных с обученным механизмом внимания и декодер (как GPT) для генерирования текста. В итоге мы получили форматные строки приличного качества (оценивали путем подсчета метрик машинного перевода), однако оказалось, что они должны быть предельно точными. Буквально символ в символ, иначе валидатор форматных строк начинает кричать об ошибках.
После множества попыток подтянуть качество seq2seq-модели мы решили подойти к задаче с другой стороны. Основная цель форматной строки — замаскировать изменяющиеся данные, чтобы шаблон оставался общим для всех событий в кластере. Значит, нужно научиться получать такие токены из строки необработанного события. Также мы отметили, что подстроки могут сразу заполняться как поля нормализации. На основе этих тезисов мы выработали новый подход:
- Составляем список подстрок, которые станут полями в SIEM.
- Определяем методы для маскирования изменяющихся подстрок.
- Формируем дополнительное условие с токеном COND.
- Находим структуру ключ-значение в сообщении и меняем ее на токен KEYVALUE.
Первая задача решается с помощью файн-тюнинга большой языковой модели на подготовленных инструкциях. Учимся делать как эксперт: по строке события получаем файл с заполненными полями в SIEM. Остальные задачи мы решили при помощи промптов: дообучили языковую модель для поиска структуры ключ-значение и использовали алгоритмическую логику. Кстати, в работе с промптами мы обязательно применяем технику с фью-шотами для получения ожидаемого ответа без галлюцинаций.
В итоге качество полученных форматных строк стало заметно выше. Кроме того, теперь мы сможем использовать логику кода и обработки данных для исправления ошибок в будущих примерах.
Для оценки результата можно использовать метрики машинного перевода, например BLEU. Но форматные строки имеют определенную вариативность в токенах, и разные эксперты могут писать их по-разному. В SIEM есть специальный набор утилит — назовем его «нормализатор». С его помощью можно оценивать сами форматные строки, XP-код и общий результат нормализации по событию. При этом мы можем получить вполне себе бинарную оценку валидации и сформировать accuracy по всей выборке правил из базы знаний.
По типу обрабатываемых событий форматные строки деляется на два типа:
- Для текстовых событий (TEXT, CEF). Accuracy — 0,98 на выборке из 873 событий.
- Для структурированных событий (JSON, TABULAR, EVENTLOG). Accuracy — 1 на выборке из 598 событий.
В алгоритме для форматных строк типа TEXT есть некоторые эвристики, поэтому в результате могут иногда появляться ошибки. Со структурированными событиями все проще, главное — правильно составить дополнительное условие в COND.
Генерирование контента
Теперь, когда кластеры сообщений сформированы, необходимо подготовить для каждого из них экспертный контент. Код для нормализации хранится в файле formula.xp (форматная строка, которая пишется в начале, уже заполнена).
Шаблон экспертного контента для кластера выглядит следующим образом:
- файлы локализации с описанием событий на соответствующем языке (файл metainfo содержит специфичную информацию, которую тоже легко сгенерировать);
- файл norm.js, в котором хранятся извлеченные подстроки, соответствующие полям по схеме SIEM;
- файл raw.txt с примером оригинального необработанного события;
- файл formula.xp с кодом нормализации, написанным на XP.
Итак, для решения задачи нам необходимо сгенерировать:
- имя правила нормализации,
- файлы локализации,
- поля нормализации для заполнения файла norm.js,
- код на языке XP для выполнения нормализации.
Первый пункт можно закрыть с помощью обычного промпта с фью-шотами примеров. С остальными сложнее: придется выполнять файн-тюнинг большой языковой модели. Что касается датасета, все правила нормализации хранятся в репозитории: с помощью несложного парсинга можно собрать выборки с инструкциями под разные задачи.
PEFT — это техника файн-тюнинга, которая улучшает результаты предварительно обученных языковых моделей. Идея в том, чтобы обучить небольшое подмножество параметров LLM, а остальные оставить замороженными. Способ имеет ряд преимуществ:
- Ускорение обучения. Вместо того, чтобы переобучать все параметры модели, можно выделить небольшую часть весов для тренировки.
- Адаптация к новым задачам. Вместо того, чтобы учить одну модель выполнять все задачи, мы получим набор разных весов для каждой из них.
- Удобство развертывания на инференсе. Веса, обученные при помощи PEFT, — компактнее. Их проще развертывать и переносить на другие устройства, они занимают меньше места и быстрее загружаются.
Самая эффективная техника проведения PEFT — LORA-тюнинг (Low-Rank Adaptation). Идея в следующем: предварительно обученная матрица весов представляется двумя меньшими матрицами, полученными путем низкоранговой аппроксимации. Их и нужно дообучать, а исходная матрица при этом остается прежней. Затем дообученные матрицы объединяются с исходной для получения обновленной матрицы весов.
Подробнее о преимуществах PEFT в режиме инференса
Фреймворк vLLM поддерживает сервинг LORA-адаптеров. Фактически дообученные веса — это новый файл, который нужно загрузить в память. При этом стандартные веса модели и построенные вокруг нее решения не пропадают. Во время выполнения конкретной задачи дообученные веса конкатенируются с основной матрицей, а затем отключаются. Все происходит на лету!
Еще одно преимущество PEFT — скорость инференса под конкретную задачу. Длинная инструкция с описаниями требований здесь не нужна, соответственно, скорость обработки повышается. А дополнительные параметры в виде температуры и вероятности распределения токенов позволяют получать вариативные ответы.
Оценка качества правил нормализации
По каждой из задач мы сформировали отдельные метрики качества для правил нормализации. Плюс заранее сформировали валидационную выборку в виде нескольких источников событий каждого типа. Эти события не участвовали в обучении, и мы рассчитывали все метрики на них.
Качество генерирования полей нормализации можно оценить с помощью метрик precision и recall. Эталонный вариант полей norm.js, сделанный экспертом, сравнивается с полученным от модели референсом.
События по типу форматной строки | Число событий в тестовой выборке | Precision | Recall |
---|---|---|---|
CEF | 89 | 0,585 | 0,670 |
TEXT | 103 | 0,716 | 0,653 |
JSON | 123 | 0,598 | 0,621 |
TABULAR | 228 | 0,658 | 0,521 |
EVENTLOG | 79 | 0,727 | 0,680 |
При оценке результатов из табл. 1 нужно учитывать несколько нюансов. Во-первых, успех засчитывался, только когда строки полностью совпадали. Модель может генерировать неидентичное заполнение, но оно будет правильным. Например, эксперт может заполнить поле reason словами «давно не выполнялся поиск вирусов», а модель — «на данном устройстве давно не выполнялся поиск вирусов». При этом для некоторых полей критично идентичное равенство (например, event_src.hostname). Во-вторых, зачастую модель верно извлекает важную подстроку, но неверно присваивает поле — все-таки в SIEM их более 170.
Качество генерирования файлов локализации оценивается схожим образом: эталонный результат эксперта vs референс модели. Однако в этом случае сравнивается не текст, а эмбеддинги, полученные BERT Score.
Файлы локализаций | Precision | Recall | F1 |
---|---|---|---|
i18n_ru | 0,905 | 0,896 | 0,900 |
i18n_en | 0,969 | 0,962 | 0,965 |
metainfo | 0,969 | 0,953 | 0,961 |
Как видим, модель научилась хорошо генерировать текст локализаций в стиле экспертов. Отметим, что при решении этой задачи нужно учитывать важный момент: модель не должна генерировать в тексте поля, которых нет в SIEM. В этом случае правило не сработает. Обученная модель всегда генерирует только те поля, которые есть в таксономии.
Наконец, переходим к XP-коду для выделения сгенерированных полей из событий. Код для текстовых (TEXT, CEF) и структурных (JSON, TABULAR, EVENTLOG) событий будут немного различаться. Дело в том, что в структурных событиях можно буквально обращаться к переменным ключей события и доставать из них нужную информацию. Кроме того, одни конструкции кода чаще фигурируют в текстовых событиях, а другие — в структурных. Чтобы не учить модель обращаться сразу и с текстовыми, и со структурными событиями, мы обучили два адаптера для генерирования XP-кода.
Для оценки качества кода мы использовали нормализатор. С его помощью можно оценить, для какого количества полей код сгенерирован правильно и работает ли он в принципе. Кроме того, нормализатор дает вполне себе внятный дебаг ошибок — вокруг него можно строить пайплайн исправления кода.
Оценивать качество сгенерированного кода метриками машинного перевода (BLEU, F-мера на символах) было бы не совсем правильно. Ведь код можно написать совершенно по-разному, и он все равно будет решать поставленную задачу. В нашем случае главные критерии качества — работает код или нет и правильно ли извлекаются нужные подстроки.
Мы взяли валидационные источники и сгенерировали XP-код для каждого кластера событий. Если определенные поля были извлечены неверно, эти строки помечались комментарием.
Тип адаптера для генерирования XP-кода | Текстовые события | Структурные события |
Число кластеров в источнике | 75 | 95 |
Число правил с успешным результатом валидации | 72 | 92 |
Вероятность получить работающее правило нормализации | 0,960 | 0,968 |
Число полей, для которых правильно сгенерирован XP код | 1617 | 1375 |
Число полей, для которых нужно получить XP код | 1795 | 1856 |
Вероятность того, что написанный код для поля правильный | 0,901 | 0,74 |
Результаты показывают, что вероятность получить работающее правило нормализации достаточно высока — это однозначно можно считать успехом. При этом можно оценить качество правильно сгенерированных конструкций кода для конкретного поля нормализации. Обратите внимание, что вероятность получить верный код для полей нормализации в структурированных источниках составляет 90%. Это логично, ведь код для подобных событий и человеку написать проще. Для текстовых источников вероятность получить правильный код для поля нормализации составляет 74%. Это точка роста и возможность для дальнейшего улучшения решения.
Конечно, для оценки валидации правил нормализации недостаточно снять метрики на нескольких источниках. Это долгий процесс тестирования и валидации на новых примерах, который ждет нас впереди. Чего мы добились на данный момент: эксперт может отправить в сервис лог-файл с событиями и получить в ответ набор правил нормализации по источнику. Пока это не end-to-end решение, но оно уже позволяет значительно снизить вовлеченность человека в процесс. В дальнейшем планируем сосредоточиться на улучшении качества компонентов сервиса и тестировании на реальных потоках данных из ненормализованных источников. Наша цель — создать систему, которая сможет адаптироваться к изменениям без постоянного вмешательства человека.