Классификаторы
Классификатор — первый объект контента, который встречает каждое входящее событие. Его единственная задача — решить, какого рода инцидент это событие, — превратить сырой payload из коннектора в тип инцидента SOARForge — до того, как отработают любой маппинг полей, обогащение или плейбук. Правильная классификация — это то, что позволяет остальному вашему контенту (layout-ам, мапперам, SLA, плейбукам) завязываться на чистый, предсказуемый тип инцидента, а не разбирать сырые вендорские поля повсюду.
Эта глава покрывает, что делает классификатор в момент ingest, полностью трёхпанельный конструктор, как именно правило сопоставляется с событием, как классификатор привязывается к инстансу интеграции, быстрый тест, а также как управлять классификаторами и делиться ими через Marketplace.
Почему это важно. Классификация сидит на горячем пути каждого алерта. Плохо настроенный классификатор не бросает ошибку — он молча отправляет события к неверному типу инцидента (или в fallback), и каждое решение ниже по потоку наследует эту ошибку. Конструктор устроен так, чтобы вы могли проверить исход на реальных событиях до того, как он дойдёт до прода.
3.1. Что делает классификатор и когда он запускается
Концепция. Классификатор читает одно или несколько полей события и определяет
тип инцидента. Он отрабатывает один раз на событие, в момент ingest, и его
вывод сохраняется как incidentTypeId кейса. Он никогда не изменяет значения полей
— это задача входящего маппера (глава 4). Классификация просто отвечает на вопрос
«какой тип?».
Когда он запускается. Алерты входят в SOARForge только через очередь ingest
(POST /ingest → exchange soar.ingest → воркер ingest). Внутри одной транзакции
базы данных воркер:
- Резолвит инстанс интеграции для события. Он сопоставляет
sourceInstanceсобытия с активными инстансами коннектора, чейsourceKeyравенsourceсобытия. Если ни один инстанс не несёт этотsourceInstance, используется инстанс без установленногоsourceInstanceкак catch-all. Если нет ни того, ни другого, событие отбрасывается (no_matching_instance) — классификация не отрабатывает и кейс не создаётся. - Запускает классификатор этого инстанса (описан ниже), чтобы получить кандидата в тип инцидента, или ничего.
- Применяет приоритет: если классификатор произвёл тип, этот тип побеждает.
Иначе используется Default Incident Type инстанса как fallback. Если
классификатор не совпал ни с чем и у инстанса нет типа по умолчанию, событие
отбрасывается (
no_default_incident_type). - Передаёт разрешённый тип инцидента входящему мапперу и создаёт кейс.
Запись на таймлайне каждого созданного кейса фиксирует, какой путь был выбран, —
classification strategy: classifier, когда решило правило (или жёстко заданный
тип), или default_incident_type, когда решил fallback.
Два режима классификатора.
- Rule-based classifier — список правил, каждое из которых состоит из условия над полями события плюс целевой тип инцидента. Именно это производит визуальный конструктор и использует большинство контента.
- Hardcoded incident type — классификатор пропускает правила вовсе и всегда возвращает один фиксированный тип инцидента. Полезно для одноцелевого фида (напр. коннектор, который производит только отчёты о фишинге).
Нет классификатора / нет совпадения. Классификатор на инстансе опционален. Без привязанного классификатора каждое событие с этого инстанса идёт прямо к Default Incident Type инстанса. С привязанным rule-based классификатором, но без правила, совпавшего с данным событием, это событие тоже проваливается к Default Incident Type. Поэтому fallback несущий — см. ошибки в §3.8.
3.2. Конструктор классификатора
Маршрут: /admin/incident-types → вкладка Classification → Classifier
(URL ?tab=classification&classificationTab=classifier) ·
Права: incident_types.view для открытия, incident_types.manage для
сохранения · Модуль: cases
К конструктору вы попадаете, кликнув Edit на строке классификатора, или New → New Incident Classifier, в библиотеке Classifiers & Mappers (§3.6). Конструктор — это трёхпанельное рабочее пространство над верхней панелью и панелью инструментов.
Верхняя панель
| Элемент | Назначение |
|---|---|
| Classifier name (текстовое поле) | Уникальное имя классификатора. Обязательно для сохранения; имена уникальны в пределах платформы. |
| Back to classification | Возвращает в библиотеку Classifiers & Mappers (библиотеку объектов). |
| Save | Сохраняет классификатор. Когда конструктор открыт из инстанса и классификатор ещё не привязан к нему, Save также привязывает классификатор к этому инстансу. Недоступно, пока не выбран коннектор. |
Отдельной кнопки «быстрый тест» на верхней панели нет — валидация payload сквозь делается в панели Test Classification (§3.5).
Панель инструментов — выбор источника событий
| Элемент | Поведение |
|---|---|
| Data source (Select) | Pull from live events, Generate sample events или Paste JSON events. |
| Quantity (1–100, по умолчанию 30) | Только для Pull. Сколько событий запросить. Ограничивается собственным max-fetch инстанса (или 50), так что превью никогда не вытянет больше, чем разрешает инстанс. |
| Sort order (newest / oldest) | Только для Pull. Превью по умолчанию newest-first. |
| Кнопка Pull / Load | Запускает выбранный загрузчик. |
| Connector (Select) | Коннектор, чьи события вы классифицируете. |
| Instance (Select) | Конкретный инстанс. Его sourceInstance — это то, чем ограничен поток событий, и (при сохранении) классификатор привязывается сюда. |
Pull from live events вызывает реальную команду fetch-incidents выбранного
инстанса — ту же команду, которую использует планировщик — так что JSON, который
вы видите, — ровно то, что принимает прод. Важны два свойства безопасности: fetch
выполняется в изолированном пространстве состояния, так что он никогда не
двигает реальный чекпоинт опроса инстанса (вытягивание превью не заставит его
пропустить или перезабрать события), и он использует фиксированное окно оглядки в
30 дней. У инстанса должны быть рабочие учётные данные; неудавшийся fetch показывает
ошибку интеграции.
Generate sample events строит синтетические события целиком в браузере (без обращения к бэкенду) — например, репрезентативные почтовые сообщения Office 365. Используйте его, чтобы проектировать и формировать правила, когда живых данных под рукой нет; структура зеркалит реальные payload коннектора.
Paste JSON events открывает модальное окно, куда вы вставляете JSON-массив
событий (или один объект). Каждое событие должно выглядеть как тело ingest —
{ source, sourceInstance, sourceRef, payload: { … } } — чтобы пути полей, которые
вы строите, совпадали с продом. Невалидный JSON отклоняется с ошибкой.
Левая панель — список событий и JSON-дерево
Левая панель показывает текущее событие как интерактивное JSON-дерево, плюс:
- Навигация по событиям — стрелки предыдущее / следующее и бейдж
index/total(напр.3/30) для пролистывания загруженных событий. - Счётчик несопоставленных значений для поля, по которому вы классифицируете.
- Поле JSON search, подсвечивающее совпадающие ключи в дереве.
Кликните любой лист или узел в дереве, чтобы задать его полем классификатора —
путём, чьи значения вы будете сопоставлять типам инцидентов. Пути конверта, такие
как source, sourceInstance и sourceRef, используются как есть; всё внутри
тела события адресуется под payload. (например, клик по alertType внутри
payload выбирает payload.alertType).
Центральная панель — поле и его значения
Центральная панель — там, где вы выбираете поле-дискриминатор и видите его значения:
- Field path (редактируемый ввод) — отражает путь, кликнутый в дереве, или наберите его напрямую. Очистка сбрасывает маппинг.
- Current result — значение этого поля в текущем отображаемом событии, чтобы вы могли проверить путь на реальной записи.
- Чипы несопоставленных значений — каждое отдельное значение, которое поле принимает по загруженным событиям, каждое с числом событий, несущих его. Эти чипы перетаскиваемы; значение исчезает из этого списка, как только оно сопоставлено типу. Когда каждое значение сопоставлено, появляется зелёное подтверждение «all classified»; когда путь не резолвится ни во что, предупреждение сообщает об этом.
- Fallback type (Select, внизу) — собственный fallback-тип инцидента классификатора. Он сохраняется на классификаторе и применяется в рантайме, когда ни одно правило не совпало, раньше Default Incident Type инстанса (приоритет §3.4). Он подставляется из Default Incident Type инстанса как стартовая точка, но то, что вы здесь сохраняете, хранится на классификаторе; оставьте пустым, чтобы сразу проваливаться на дефолт инстанса.
Правая панель — типы инцидентов (зоны сброса правил)
Правая панель перечисляет ваши типы инцидентов, каждый как зону сброса. Перетащите чип значения из центральной панели на карточку типа инцидента, чтобы создать правило: «когда поле равно этому значению, классифицировать как этот тип». Каждая карточка показывает счётчик значений, сопоставленных ей, и перечисляет их как удаляемые теги; кликните ✕ у тега, чтобы отсопоставить значение.
Что пишет Save. Конструктор превращает вашу карту значение→тип в rule-based
классификатор: каждое сопоставленное значение становится одним правилом с условием
{ all: [ { path: <field>, equals: <value> } ] }, целевым типом инцидента и
приоритетом 100. Перетаскиваемое значение сохраняет свой тип JSON — числовое
значение события пишется числом, булево — булевым, текст — текстом (значение,
встреченное с разными типами в выборке, деградирует к тексту), — так что правило
совпадает с живым событием без несовпадения типов.
Подлежащий движок поддерживает более богатый язык условий (§3.3), которым могут пользоваться классификаторы, поставляемые Marketplace. Drag-and-drop конструктор по-прежнему редактирует только правила точного значения над одним полем, но сохраняет без потерь любые более сложные правила, которые не умеет редактировать: продвинутые правила сохраняются байт-в-байт при Save и показываются как чипы только для чтения «N advanced rules» на карточках типов инцидентов (наведите, чтобы увидеть используемые операторы). Поэтому сохранение пакетного классификатора из конструктора больше не уплощает его продвинутые правила — но конструктор всё ещё не является их редактором (§3.8).
3.3. Как правило сопоставляется с событием
Понимание точной семантики сопоставления — это то, что отличает классификатор, который «выглядит правильно», от того, который действительно срабатывает. Это логика, которую гоняет воркер ingest; быстрый тест (§3.5) гоняет ту же логику.
Условие правила — небольшое дерево выражений. Лист имеет path плюс один
или несколько операторов; все операторы, присутствующие на листе, должны
выполниться, чтобы лист совпал:
| Оператор | Совпадает, когда… | Примечания |
|---|---|---|
equals |
значение равно цели | Свободное скалярное сравнение: после быстрого пути строгого ===, если обе стороны — примитивы (строка/число/булево), сравниваются их текстовые формы, так что "3" совпадает с числом 3. По-прежнему чувствителен к регистру ("Phishing" ≠ "phishing"). Объекты/массивы/null никогда не приводятся. |
notEquals |
значение не равно | Свободное скалярное сравнение, как выше. |
in |
значение — одно из списка | Свободная скалярная принадлежность; применяется, только когда список непуст. |
notIn |
значения нет в списке | Как выше. |
contains |
текст содержит подстроку | Нечувствителен к регистру; значение сначала приводится к тексту. |
regex |
текст совпадает с регулярным выражением | Нечувствителен к регистру по умолчанию; поддерживает inline-префикс флага в стиле (?i); невалидный паттерн просто не совпадает. |
exists |
поле присутствует | «Присутствует» означает не undefined, не null и не пустую строку. |
Комбинирование листьев. Условия могут вкладываться тремя комбинаторами:
all— каждое подусловие должно совпасть (логическое AND). Пустойallне совпадает ни с чем.any— хотя бы одно подусловие должно совпасть (логическое OR).not— отрицает своё подусловие.
Резолвинг путей. Пути разделены точками (payload.event.type). Числовой
сегмент индексирует массив (payload.items.0.id); нечисловой сегмент,
применённый к массиву, проецируется по каждому элементу и собирает значения. Пути
правил резолвятся относительно контекста события, который экспонирует payload.*
(сырое тело события) плюс поля конверта source, sourceInstance, sourceRef,
name, details и rawJSON.*.
Какое правило побеждает. Классификатор оценивает правила по порядку. Когда stop-on-first-match включён (по умолчанию), побеждает первое совпавшее правило, и оценка на этом останавливается. С выключенным stop-on-first-match оцениваются все правила, и побеждает правило с наивысшим приоритетом, ничьи разрешаются по позиции (побеждает верхнее правило). Поскольку визуальный конструктор пишет каждое правило с приоритетом 100 и включённым stop-on-first-match, сделанные конструктором классификаторы оцениваются сверху вниз, и каждое отдельное значение сопоставляется ровно одному типу — так что на практике решает первое совпавшее значение. Используйте приоритет только тогда, когда сами пишете пересекающиеся правила с выключенным stop-on-first-match.
Если ни одно правило не совпало, классификатор применяет свой собственный fallback-тип инцидента (§3.2), если он задан; иначе берёт верх Default Incident Type инстанса, и только если не задано ни то ни другое, событие отбрасывается (приоритет §3.4).
3.4. Привязка классификатора к инстансу интеграции
Классификатор ничего не делает, пока на него не укажет инстанс. Привязка происходит в Advanced settings инстанса коннектора (Settings → Integrations → Connectors → инстанс → Advanced Settings), где вместе живут три связанных поля:
- Classifier — классификатор, который этот инстанс гоняет в момент ingest.
- Default Incident Type — fallback-тип уровня инстанса, используемый, когда классификатор (правила и его собственный fallback) не выдал ничего, или когда классификатора нет.
- Incoming Mapper — маппер, который заполняет поля, как только тип решён.
Приоритет (проверено в пути ingest):
- Совпадение классификатора (срабатывание правила или жёстко заданный тип) — наивысший.
- Иначе собственный fallback-тип инцидента классификатора (§3.2), если задан.
- Иначе Default Incident Type инстанса.
- Иначе событие отбрасывается и кейс не создаётся.
Один классификатор на инстанс. Инстанс гоняет ровно один классификатор. Если у
одного коннектора несколько инстансов (например, два почтовых ящика Office 365),
каждый инстанс может привязать свой классификатор, и sourceInstance события
выбирает, какой инстанс — а значит, какой классификатор — применяется.
Сохранение из конструктора, пока он был открыт в контексте инстанса, привязывает классификатор к этому инстансу автоматически. Можно также задать или сменить привязку прямо из Advanced settings инстанса.
3.5. Тестирование классификатора — панель Test Classification
Маршрут: /admin/incident-types → Classification →
?classificationTab=test · Право: incident_types.manage
Панель Test Classification прогоняет образец payload через реальный конвейер, чтобы вы могли подтвердить исход, прежде чем ему доверять.
- Выберите Connector и Instance. Тест резолвит инстанс тем же способом, что и ingest, затем гоняет классификатор этого инстанса.
- Вставьте образец payload ingest —
{ source, sourceInstance?, sourceRef?, payload: { … } }. Панель переопределяетsource/sourceInstanceиз вашего выбора, чтобы использовался правильный инстанс. - Нажмите Run Test.
Результат показывает по порядку, что решил конвейер:
- Classified as
<incident type>— и, когда решило правило, подпись совпавшего правила (Rule N). Когда решил собственный fallback классификатора, появляется тег via classifier fallback; когда решил Default Incident Type инстанса — тег via instance default. - No classification rule matched this payload — когда ни правило, ни fallback классификатора, ни дефолт инстанса не произвели тип.
- Pipeline source — совпал ли вообще активный инстанс коннектора. (Классификация строга: если ни один инстанс не совпал, legacy-fallback нет — событие было бы отброшено в проде.)
- Mapped Fields Preview — превью вывода входящего маппера для разрешённого типа инцидента, чтобы вы видели классификацию и маппинг вместе.
Тест — самый быстрый способ поймать две самые частые ошибки: путь поля, который не резолвится в реальных событиях, и значение, которое не совпадает из-за типа или регистра (§3.8).
3.6. Управление классификаторами
Маршрут: /admin/incident-types → Classification (представление по
умолчанию, ?classificationTab=objects) · Права: incident_types.view,
incident_types.manage
Классификаторами управляют бок о бок с мапперами в библиотеке Classifiers & Mappers — единой таблице всех объектов классификации.
| Колонка | Значение |
|---|---|
| Name | Имя объекта (кликните, чтобы открыть его редактор). |
| Type | Classifier, Mapper (incoming) или Mapper (outgoing). |
| Instances | Сколько инстансов интеграций сейчас используют этот объект. |
| Description | Для классификатора: его режим и число правил. |
| System | True, когда объект поставлен content-паком (а не рукотворный custom-объект). |
Панель действий предлагает Edit (открывает конструктор), Clone, Delete и New (выпадающее: New Incident Classifier / Incoming Mapper / Outgoing Mapper). Поле поиска фильтрует по имени, бренду или описанию.
Clone. Клонирование создаёт независимую custom-копию с именем <name> (copy). Копия сохраняет правила, режим и бренд интеграции, но никогда не помечается
как дефолт бренда и всегда стартует как custom, оставаясь полностью
редактируемой. Clone — правильный способ адаптировать поставленный паком
классификатор: отредактируйте копию и привяжите её к своему инстансу, оставив
управляемый оригинал нетронутым.
Delete. Удаление отклоняется, пока какой-либо инстанс всё ещё ссылается на классификатор (API возвращает конфликт). Сначала отвяжите его от Advanced settings каждого инстанса, затем удаляйте. Действие защищено диалогом подтверждения.
Как паки Marketplace поставляют классификаторы. Content-паки бандлят классификаторы (вместе с типами инцидентов, мапперами и плейбуками). Установка или обновление пака апсертит каждый классификатор по его уникальному имени:
- Классификатор, чьё имя новое для вашей инсталляции, создаётся со своим полным набором правил и помечается как pack-managed (показывает System = True).
- Классификатор, чьё имя уже существует, при обновлении не перезаписывается по правилам — обновление лишь освежает его пометку brand/managed. Это защищает локальные правки одноимённого классификатора, но это же означает, что обновление пака не может протолкнуть изменения правил в классификатор, который у вас уже есть под этим именем.
Из-за этого устойчивый паттерн кастомизации контента пака: Clone классификатор пака в custom-копию, отредактируйте копию и привяжите копию к своему инстансу. Ваша кастомизация тогда переживает обновления пака, а оригинал остаётся управляемым.
3.7. Разобранный пример
Допустим, почтовый коннектор Office 365 подаёт события вроде такого:
{
"source": "office365_graph",
"sourceInstance": "soc-mailbox",
"sourceRef": "graph-abc-1",
"payload": {
"alertType": "phishing",
"subject": "Urgent MFA reset password request",
"severity": "high"
}
}
Вы классифицируете по полю payload.alertType с двумя правилами:
| Правило | Условие | Целевой тип инцидента |
|---|---|---|
| Rule 1 | payload.alertType equals phishing |
Phishing |
| Rule 2 | payload.alertType equals malware |
Malware |
Default Incident Type инстанса (fallback) — Generic Alert.
Исходы:
- Событие выше имеет
alertType = "phishing"→ совпадает Rule 1 → кейс — инцидент Phishing. - Событие с
alertType = "malware"→ совпадает Rule 2 → Malware. - Событие с
alertType = "bruteforce"→ ни одно правило не совпало → fallback → Generic Alert. - Событие с отсутствующим
alertType→ ни одно правило не совпало → fallback → Generic Alert. - Событие с
alertType = "Phishing"(с большой P) → ни одно правило не совпало (equalsчувствителен к регистру) → fallback → Generic Alert. Если вам нужно толерантное сопоставление, инструмент — рукописное правилоcontains/regex(нечувствительное к регистру), а неequals.
Прогоните каждое из этого через панель Test Classification (§3.5), чтобы увидеть точное решение и превью сопоставленных полей до сохранения.
3.8. Распространённые ошибки
- Путь поля отсутствует или набран с ошибкой в реальных событиях. Классификатор, привязанный к пути, который никогда не резолвится, не совпадает ни с чем, так что каждое событие молча попадает на fallback-тип. Подтвердите путь через Pull from live events: чипы значений появляются только для значений, которые путь действительно производит, а Current result показывает значение в каждом событии. Быстрый тест показывает то же.
- Тип значения (числа и булевы) — теперь обрабатывается. Конструктор сохраняет
тип JSON перетаскиваемого значения, а движок к тому же делает свободное
скалярное сравнение, так что классификация по числовому полю (напр.
severity: 3) совпадает с числом3, хранит ли правило3или"3". Строковые дискриминаторы (alertType,category) по-прежнему самый ясный выбор, но числовой/булев дискриминатор теперь работает; проверяйте быстрым тестом как обычно. - Чувствительность к регистру.
equals/notEquals/inточны и чувствительны к регистру.containsиregexнечувствительны к регистру. Для значений, чей регистр варьируется по фиду, рукописное правилоcontains/regexнадёжнее набора правилequals. - Нет fallback → отброшенные события. Если классификатор не совпадает ни с чем,
а у инстанса нет Default Incident Type, событие отбрасывается
(
no_default_incident_type) и кейс не создаётся. Всегда задавайте Default Incident Type инстанса, чтобы несовпавшие события всё равно всплывали. - Нет совпадающего инстанса → отброс до классификации. Если
source/sourceInstanceсобытия не резолвится в активный инстанс, событие отбрасывается (no_matching_instance) и классификатор не отрабатывает. Проверьте, что инстанс Active и что егоsourceInstanceсовпадает с событиями. - Редактирование pack-owned классификатора на месте. Визуальный конструктор
может редактировать только правила
equalsнад одним полем, но теперь сохраняет без потерь продвинутые правила (contains,regex,any/all, многополевые): они сохраняются при Save и показываются как чипы только для чтения «N advanced rules» на карточках типов инцидентов, так что Save больше не роняет их молча. Редактировать эти правила в конструкторе всё ещё нельзя — чтобы изменить продвинутые правила классификатора пака, Clone его и отредактируйте JSON, или правьте через API. (Обновления пака по-прежнему не перезаписывают правила одноимённого классификатора.) - Селектор Fallback теперь персистит. Поле Fallback type в конструкторе — собственный fallback-тип инцидента классификатора: Save хранит его на классификаторе, и в рантайме он применяется раньше Default Incident Type инстанса, когда ни одно правило не совпало (приоритет §3.4). Оставьте пустым, чтобы сразу проваливаться на дефолт инстанса; Default Incident Type инстанса по-прежнему задаётся в Advanced settings инстанса.
- Удаление классификатора, который всё ещё привязан. Удаление отклоняется, пока какой-либо инстанс ссылается на классификатор. Сначала отвяжите его из Advanced settings каждого инстанса.