Как wallarm анализирует запросы

Wallarm следует принципу, что для качественного анализа запросов WAF'ом необходимо

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

Например, если приложение предоставляет JSON API, то обрабатываемые им параметры будут закодированы в JSON-формате. Для анализа запросов к такому API необходимо разобрать JSON для получения значений, которые будут использоваться приложением. Бывают и более сложные случаи, когда данные кодируются несколько раз, например JSON в BASE64 в JSON.

Под контекстом обработки данных подразумевается, что один и тот же параметр может по разному обрабатываться разными частями приложения. Например, параметр name может передаваться в запросах на создание как товара, так и пользователя. Но код обработки этих запросов мог быть написан разными разработчиками в соответствии с разными требованиями. При описании API обычно используется термин эндпойнт, в дальнейшем мы будем придерживаться его.

С учетом вышеперечисленного можно считать, что в процессе анализа запросов есть следующие этапы:

  • определение формата и парсинг каждого параметра;
  • подсчет метрик, позволяющих сделать вывод о наличии атаки, для каждого параметра;
  • определение эндпойнта, на который направлен запрос;
  • сравнение посчитанных метрик с нормами для этого эндпойнта.

Парсинг параметров

Начиная с верхнего уровня (всего HTTP-запроса) фильтрующий узел последовательно пытается применить к каждому из параметров все подходящие парсеры. Результатом применения парсера является дополнительный набор параметров, которые необходимо анализировать аналогичным образом.

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

Список применяемых парсеров зависит от характера данных и результатов предыдущего обучения системы.

URL

Каждый HTTP-запрос содержит в себе URL.

Для поиска атак, фильтрующий узел обрабатывает URL анализирует как исходное значение целиком, так и отдельные его компоненты. При составлении правил предпочтительнее использовать отдельные компоненты URL, так как это позволяет системе применять правила более эффективно.

URL-парсер предоставляет следующие фильтры, применяемые к HTTP-запросу:

  • url — строка с исходным значением URL;
  • path — массив с частями URL, разделенными /, кроме последней. Если в URL'е есть только одна часть, то будет пустой массив;
  • action_name — последняя часть URL после / и до первой точки (.). В запросе всегда присутствует, даже если значение — пустая строка;
  • action_ext — последняя часть URL после / после первой точки (.). В запросе может отсутствовать;
  • get — параметры после ?. Ниже мы рассмотрим их подробнее.

Например, в запросе /blogs/123/index.php?q=aaa будут следующие параметры:

  • [url] — /blogs/123/index.php?q=aaa;
  • [path, 0] — blogs;
  • [path, 1] — 123;
  • [action_name] — index;
  • [action_ext] — php;
  • [get, 'q'] — aaa.

GET-параметры

Если приложению передаются GET-параметры, то их названия и значения включаются непосредственно в URL запроса после символа ?. Как правило, значения передаются в формат ключ-значение, но может использоваться и более сложная структура.

Например, в запросе /?q=some+text&check=yes передаются следующие параметры:

  • [get, 'q'] — some text;
  • [get, 'check'] — yes.

Пример сложной структуры параметров в запросе /?p1[x]=1&p1[y]=2&p2[]=aaa&p2[]=bbb:

  • [get, 'p1', hash, 'x'] — 1;
  • [get, 'p1', hash, 'y'] — 2;
  • [get, 'p2', array, 0] — aaa;
  • [get, 'p2', array, 1] — bbb.

Кроме этого, некоторые веб-сервера поддерживают pollution, когда значение одноименных параметров объединяются. Например, в случае, если веб-сервер поддерживает pollution, то параметры в запросе /?p3=1&p3=2 раскладываются в следующий вид:

  • [get, 'p3', array, 0] — 1;
  • [get, 'p3', array, 1] — 2;
  • [get, 'p3', pollution] — 1,2.

Заголовки

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

Фильтр для получения заголовков называется header, и он всегда приводит названия заголовков к верхнему регистру.

Для заголовков также поддерживается pollution.

Например, в запросе

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-запроса;
  • proto — версия HTTP-протокола;
  • scheme — http/https;
  • instance — ID приложения.

Base64

Парсер Base64 может применяться к любой строке и предоставляет одноименный фильтр.

Например, параметры могут выглядеть следующим образом:

  • [get, 'token', base64];
  • [post, multipart, 'data', base64].

Cookies

Значение заголовка Cookie обрабатывается особым образом и приложением, и фильтрующим узлом. Значение парсится с помощью 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, то отдельные параметры доступны при помощи фильтра form_urlencoded. Поддерживаются имена со сложной структурой и pollution.

Например, в запросе

...
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.

Gzip

Парсер Gzip может применяться к любой строке и предоставляет одноименный фильтр.

Например, параметры могут выглядеть следующим образом:

  • [get, 'token', base64, gzip];
  • [post, multipart, 'data', gzip].

JSON

JSON позволяет кодировать данные со сложной структурой и предоставляет следующие фильтры:

  • 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.

Multipart

Данные в теле запроса могут передаваться в формате multipart. В запросе, аналогичном примеру для Form-Urlencoded, будут следующие параметры:

  • [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] — содержимое файла.

Percent

Парсер Percent применяется к исходной строке с URL и производит URL-декодирование символов.

параметр выглядит следующим образом:

  • [url, percent].

Viewstate

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

Предоставляет следующие фильтры:

  • viewstate — верхнеуровневый контейнер для viewstate данных;
  • viewstate_array — массив;
  • viewstate_pair — массив;
  • viewstate_triplet — массив;
  • viewstate_dict — ассоциативный массив;
  • viewstate_dict_key — строка;
  • viewstate_dict_value — строка;
  • viewstate_sparse_array — ассоциативный массив.

XML

XML позволяет кодировать данные со сложной структурой и предоставляет следующие фильтры:

  • xml — верхнеуровневый контейнер для XML данных;
  • xml_comment — массив с комментариями в теле XML документа;
  • xml_dtd — Адрес используемой внешней DTD-схемы;
  • xml_dtd_entity — массив с определенными в документе DTD Entity;
  • xml_pi — массив инструкций для обработки;
  • xml_tag — ассоциативный массив тэгов;
  • xml_tag_array — массив значений тэга, можно использовать алиас array;
  • xml_attr — ассоциативный массив атрибутов. Может использоваться только после фильтра тэга.

Для 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.

Эндпойнты и нормы

Для принятия решения о блокировке запроса необходимо проверить, что посчитанные для каждого параметра метрики не выходят за допустимые пределы. Допустимые пределы или нормы метрик задаются в файле ЛОМ для каждого эндпойнта.

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

Например, чтобы описать эндпойнт для запросов к example.com/admin/index.php, необходимо сформировать следующие условия:

  • [header, 'HOST'] = example.com;
  • [path, 0] = admin;
  • [path, 1] отсутствует;
  • [action_name] = index;
  • [action_ext] = php.

Для ускорения определения эндпойнта в ЛОМе используется аналог дерева принятия решений. При описании частично пересекающихся эндпойнтов размер ЛОМ-файла может резко вырасти из-за комбинаторного взрыва.

Нормы можно описывать для:

  • значений параметров, например [get, 'id'];
  • значений всех параметров, например, [get_all];
  • значений по умолчанию, например, [get_default];
  • имен параметров, например, [get_name].

results matching ""

    No results matching ""