Перейти к содержанию

Анализ и парсинг запросов

Принципы анализа и парсинга запросов

Для качественного анализа запросов, Вебмониторэкс WAF следует принципам:

  • Работа с теми же данными, которые обрабатывает защищаемое приложение. Например:

    Если приложение предоставляет JSON API, параметры запроса к приложению будут закодированы в формате JSON. Чтобы получить значения параметров, Вебмониторэкс WAF применяет к запросу парсер JSON. В более сложных случаях, данные могут быть закодированы несколько раз, например: JSON в BASE64 в JSON. Тогда к запросу применяется несколько парсеров.

  • Анализ контекста обработки данных. Например:

    Параметр name передается в запросах на создание пользователя и на создание товара, при этом параметр обрабатывается двумя разными способами. Чтобы определить способ анализа подобного параметра, Вебмониторэкс WAF может использовать URL, на который отправлен запрос, или другие параметры.

Определение и парсинг частей запроса

Начиная с верхнего уровня HTTP‑запроса, WAF‑нода последовательно применяет к каждой части запроса все подходящие парсеры. Набор парсеров зависит от характера данных и результатов предыдущего обучения системы.

Результатом применения парсера является дополнительный набор параметров, которые необходимо анализировать аналогичным образом. На выходе могут получиться данные сложной структуры, например: массив, ассоциативный массив или JSON.

Теги для парсеров

Каждому парсеру присвоен идентификатор (тег). Например: header для парсера заголовков запроса. Набор тегов, использованных при анализе запроса, отображается в Консоли управления Вебмониторэкс в информации о событии. Эти данные позволяют определить, в какой части запроса обнаружена атака и какие парсеры были применены.

Например, если признаки атаки были обнаружены в заголовке SOAPACTION:

Пример тега

URL

Каждый HTTP‑запрос содержит URL. Для поиска атак, WAF‑нода анализирует исходное значение URL целиком и отдельные компоненты URL: path, action_name, action_ext, query.

Парсеру URL соответствуют теги:

  • uri для полного URL запроса без адреса домена (например, /blogs/123/index.php?q=aaa для запроса, отправленного на адрес http://example.com/blogs/123/index.php?q=aaa).

  • path для массива с частями URL, разделенными /, кроме последней. Если URL состоит только из одной части, массив будет пустым.

  • action_name для последней части URL после / и до первой точки (.). Всегда присутствует в запросе, даже если значение — пустая строка.

  • action_ext для последней части URL после / после первой точки (.). Может отсутствовать в запросе.

    Граница между action_name и action_ext при нескольких точках

    Если в последней части URL после / есть несколько точек (.), могут возникнуть проблемы при определении границы между action_name и action_ext , такие как:

    • Установка границы по первой точке, например:

      /modern/static/js/cb-common.ffc63abe.chunk.js.map

      • ...
      • action_namecb-common
      • action_extffc63abe.chunk.js.map
    • Исчезновение некоторых элементов после парсинга, для примера выше результат может быть таким:

      • action_namecb-common
      • action_extffc63abe

    Чтобы исправить ошибки, вручную отредактируйте элементы action_name и action_ext в расширенной форме конструктора URI.

  • query для параметров URL после ?.

Например, запрос /blogs/123/index.php?q=aaa содержит параметры:

  • [uri]/blogs/123/index.php?q=aaa

  • [path, 0]blogs

  • [path, 1]123

  • [action_name]index

  • [action_ext]php

  • [query, 'q']aaa

Параметры URL

Параметры URL передаются после символа ? в формате ключ=значение. Парсеру соответствует тег query.

Пример запроса Параметры URL и значения
/?q=some+text&check=yes
  • [query, 'q']some text
  • [query, 'check']yes
/?p1[x]=1&p1[y]=2&p2[]=aaa&p2[]=bbb
  • [query, 'p1', hash, 'x']1
  • [query, 'p1', hash, 'y']2
  • [query, 'p2', array, 0]aaa
  • [query, 'p2', array, 1]bbb
/?p3=1&p3=2
  • [query, 'p3', array, 0]1
  • [query, 'p3', array, 1]2
  • [query, 'p3', pollution]1,2

Заголовки

В HTTP‑запросе и некоторых других форматах (например, multipart) могут встречаться заголовки. Парсеру соответствует тег header. Все названия заголовков приводятся к верхнему регистру.

Пример:

GET / HTTP/1.1
Host: example.com
X-Test: aaa
X-Test: bbb
  • [header, 'HOST']example.com

  • [header, 'X-TEST', array, 0]aaa

  • [header, 'X-TEST', array, 1]aaa

  • [header, 'X-TEST', pollution]aaa,bbb

Метаданные

Парсеру метаданных HTTP‑запроса соответствуют теги:

  • post для тела HTTP‑запроса

  • method для метода HTTP‑запроса: GET, POST, PUT, DELETE

  • proto для версии HTTP‑протокола

  • scheme: http/https

  • application для ID приложения

Дополнительные парсеры

Части запроса могут требовать дополнительного парсинга. Например, если данные закодированы по стандарту Base64 или представлены в формате массива. Тогда к частям запроса применяются дополнительные парсеры, которым соответствуют теги ниже.

base64

Декодирует данные в кодировке Base64. Применяется к любой части запроса.

gzip

Декодирует данные в кодировке GZIP. Применяется к любой части запроса.

htmljs

Конвертирует символы HTML и JS в текстовый формат. Применяется к любой части запроса.

Пример: "aaa" конвертируется в "aaa".

json_doc

Парсит данные, представленные в формате JSON. Применяется к любой части запроса.

Фильтры:

  • json_array или array — значение элемента массива

  • json_obj или hash — значение ключа ассоциативного массива (ключ:значение)

Пример:

{"p1":"value","p2":["v1","v2"],"p3":{"somekey":"somevalue"}}
  • [..., json_doc, hash, 'p1']value

  • [..., json_doc, hash, 'p2', array, 0]v1

  • [..., json_doc, hash, 'p2', array, 1]v2

  • [..., json_doc, hash, 'p3', hash, 'somekey']somevalue

xml

Парсит данные в формате XML. Применяется к любой части запроса.

Фильтры:

  • xml_comment — массив с комментариями в теле XML документа

  • xml_dtd — адрес используемой внешней DTD-схемы

  • xml_dtd_entity — массив с определенными в документе DTD Entity

  • xml_pi — массив инструкций для обработки

  • xml_tag или hash — ассоциативный массив тэгов

  • xml_tag_array или array — массив значений тэга

  • xml_attr — ассоциативный массив атрибутов, может использоваться только после xml_tag

Для XML‑парсера нет разницы между содержимым тэга и первым элементом в массиве значений для тэга. То есть, параметры [..., xml, xml_tag, 't1'] и [..., xml, xml_tag, 't1', array, 0] идентичны и взаимозаменяемы.

Пример:

<?xml version="1.0"?>
<!DOCTYPE foo [<!ENTITY xxe SYSTEM "aaaa">]>
<?xml-stylesheet type="text/xsl" href="style.xsl"?>
<!-- test -->
<methodCall>
  <methodName>&xxe;</methodName>
  <methodArgs check="true">123</methodArgs>
  <methodArgs>234</methodArgs>
</methodCall>
  • [..., xml, xml_dtd_entity, 0] — name = xxe, value = aaaa

  • [..., xml, xml_pi, 0] — name = xml-stylesheet, value = type="text/xsl" href="style.xsl"

  • [..., xml, xml_comment, 0]test

  • [..., xml, xml_tag, 'methodCall', xml_tag, 'methodName']aaaa

  • [..., xml, xml_tag, 'methodCall', xml_tag, 'methodArgs']123

  • [..., xml, xml_tag, 'methodCall', xml_tag, 'methodArgs', xml_attr, 'check']true

  • [..., xml, xml_tag, 'methodCall', xml_tag, 'methodArgs', array, 1]234

array

Парсит массивы данных. Применяется к любой части запроса.

Пример:

/?p1[x]=1&p1[y]=2&p2[]=aaa&p2[]=bbb
  • [query, 'p2', array, 0]aaa

  • [query, 'p2', array, 1]bbb

hash

Парсит ассоциативные массивы данных (ключ:значение). Применяется к любой части запроса.

Пример:

/?p1[x]=1&p1[y]=2&p2[]=aaa&p2[]=bbb
  • [query, 'p1', hash, 'x']1

  • [query, 'p1', hash, 'y']2

pollution

Объединяет несколько значений одного параметра в массив. Применяется к любой части запроса в первоначальном виде или после декодирования.

Пример:

/?p3=1&p3=2
  • [query, 'p3', pollution]1,2

percent

Декодирует символы URL. Применяется только к компоненту URL — uri.

Парсит cookie-параметры запроса. Применяется только к заголовкам запроса.

Пример:

GET / HTTP/1.1
Cookie: a=1; b=2
  • [header, 'COOKIE', cookie, 'a'] = 1;

  • [header, 'COOKIE', cookie, 'b'] = 2.

form_urlencoded

Парсит тело запроса, переданное в формате application/x-www-form-urlencoded. Применяется только к телу запроса.

Пример:

p1=1&p2[a]=2&p2[b]=3&p3[]=4&p3[]=5&p4=6&p4=7
  • [post, form_urlencoded, 'p1']1

  • [post, form_urlencoded, 'p2', hash, 'a']2

  • [post, form_urlencoded, 'p2', hash, 'b']3

  • [post, form_urlencoded, 'p3', array, 0]4

  • [post, form_urlencoded, 'p3', array, 1]5

  • [post, form_urlencoded, 'p4', array, 0]6

  • [post, form_urlencoded, 'p4', array, 1]7

  • [post, form_urlencoded, 'p4', pollution]6,7

grpc

Парсит параметры запроса к API по протоколу gRPC. Применяется только к телу запроса.

Поддерживает фильтр protobuf для данных в формате Protocol Buffers.

multipart

Парсит тело запроса, переданное в формате multipart. Применяется только к телу запроса.

Поддерживает фильтр header для заголовков в теле запроса.

Пример:

p1=1&p2[a]=2&p2[b]=3&p3[]=4&p3[]=5&p4=6&p4=7
  • [post, multipart, 'p1']1

  • [post, multipart, 'p2', hash, 'a']2

  • [post, multipart, 'p2', hash, 'b']3

  • [post, multipart, 'p3', array, 0]4

  • [post, multipart, 'p3', array, 1]5

  • [post, multipart, 'p4', array, 0]6

  • [post, multipart, 'p4', array, 1]7

  • [post, multipart, 'p4', pollution]6,7

Если в заголовке Content-Disposition указано имя файла, то считается, что в этом параметре загружается файл, и параметр будет выглядеть следующим образом:

  • [post, multipart, 'someparam', file] — содержимое файла

viewstate

Предназначен для анализа состояния сессии, технологии, которая используется в Microsoft ASP.Net. Применяется только к телу запроса.

Фильтры:

  • viewstate_array — массив

  • viewstate_pair — массив

  • viewstate_triplet — массив

  • viewstate_dict — ассоциативный массив

  • viewstate_dict_key — строка

  • viewstate_dict_value — строка

  • viewstate_sparse_array — ассоциативный массив

jwt

Декодирует JWT. Применяется к любой части запроса.

Парсер jwt возвращает результат в виде параметров, перечисленных ниже. Набор параметров соответствует структуре JWT.

  • jwt_prefix: один из поддерживаемых префиксов JWT — lsapi2, mobapp2, bearer. Парсер декодирует значение префикса в любом регистре.

  • jwt_header: заголовок JWT. После декодирования с помощью парсера jwt, часто к значению также применяется парсер base64 или json_doc.

  • jwt_payload: набор полей в JWT. После декодирования с помощью парсера jwt, часто к значению также применяется парсер base64 или json_doc.

JWT могут быть переданы в любой части запроса. Перед применением парсера jwt, Вебмониторэкс декодирует часть запроса, в которой передано значение JWT. Для этого может использоваться парсер query или header или другой.

Пример JWT, переданного в заголовке Authentication:

Authentication: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
  • [header, AUTHENTICATION, jwt, 'jwt_prefix']Bearer

  • [header, AUTHENTICATION, jwt, 'jwt_header', base64, json_doc, hash, 'alg']HS256

  • [header, AUTHENTICATION, jwt, 'jwt_header', base64, json_doc, hash, 'typ']JWT

  • [header, AUTHENTICATION, jwt, 'jwt_payload', base64, json_doc, hash, 'sub']1234567890

  • [header, AUTHENTICATION, jwt, 'jwt_payload', base64, json_doc, hash, 'name']John Doe

  • [header, AUTHENTICATION, jwt, 'jwt_payload', base64, json_doc, hash, 'iat']1516239022

При описании части запроса, к которой должно применяться правило:

  • Сначала выберите парсер, соответствующий части запроса с JWT

  • В значении парсера jwt укажите название параметра jwt_*, к которому должно применяться правило

Пример для поля JWT name:

JWT param desc in a rule

Нормы

Нормы применяются к парсерам для array и keys типов данных. Нормы используются для определения границ анализа данных. Значение нормы указывается в названии парсера. Например: hash_all, hash_name.

Если норма не указана в явном виде, парсеру передается идентификатор сущности для обработки. Например: после hash передается название объекта JSON или другой идентификатор.

all

Используется для получения значений всех элементов, параметров или объектов. Например:

  • query_all для значений всех параметров URL

  • header_all для значений всех заголовков

  • array_all для значений всех элементов массива

  • hash_all для значений всех объектов JSON или атрибутов XML

name

Используется для получения названий всех элементов, параметров или объектов. Например:

  • query_name для названий всех параметров URL

  • header_name для названий всех заголовков

  • hash_name для названий всех объектов JSON или атрибутов XML