Пару недель назад команда Vulners опубликовала сравнение нескольких популярных WAF. Поймав себя на мысли - "а как оценивать качество его работы?", я решил разобрать подробнее тему security-тестов и критериев оценки Web Application Firewall. Статья пригодится, в первую очередь, тем, кому интересна тема веб-безопасности, ровно как и счастливым обладателям WAF.
Критерии оценки
Сравнивая различные решения, мы привыкли ориентироваться на показатели скорости и стабильности работы, удобства настройки, управления, обновления и масштабирования. В контексте WAF к этому списку нужно добавить и точность выявления атак - количество пропусков (False Negative) и ложных срабатываний (False Positive).
Зоопарк из UTF-8
Чтобы понять, сколько тонкостей существует при анализе запросов, рассмотрим в качестве примера особенность работы с UTF-8. Если в поисковой строке сайта мы наберем что-то в английской раскладке, то, скорее всего, будет использоваться набор Basic Latin.
UTF-8: Basic LatinПри этом запрос, который будет передаваться в веб-приложение,
выглядит следующим образом: GET /?s=test
Теперь попробуем использовать набор символов из Halfwidth and Fullwidth Forms (ищем тот же test, только в другой кодировке).
UTF-8: Halfwidth and Fullwidth FormsВыглядит так, будто мы использовали пробел между символами, но на самом деле - нет.
Используем другой набор символов и получаем тот же результат в поисковой выдачеЗапрос (в URLencode): GET
/?s=%EF%BD%94%EF%BD%85%EF%BD%93%EF%BD%94
При этом оба запроса (с разными наборами символов) приведут к выводу одного и того же результата - объекта, содержащего вхождение "test", хотя используем разный набор символов.
Меняем "test" на "tes1", чтобы убедиться в корректности работы поиска - ничего не выводитсяСперва мы подумали, что само веб-приложение (проверяли на
WordPress, но отработает и на других) производит нормализацию
данных до Basic Latin, но в итоге выяснили, что данные передаются
без нормализации напрямую в БД. Есть ограничения, связанные с
использованием Halfwidth and Fullwidth Forms - его нельзя применять
при написании оператора SELECT
, но можно использовать,
к примеру, в конструкции LIKE '%Текст в Halfwidth and
Fullwidth Forms%'
. Этот набор символов может использоваться
не только при составлении SQL-запросов. Есть примеры его применения
при поиске XSS и т.д.
Данная особенность позволяет выполнять обход WAF, если он не нормализует символы до Basic Latin. Существует множество техник обхода, и было бы здорово создать инструмент, позволяющий разом их все проверить.
WAF Bypass: инструментарий
На github можно найти множество решений, позволяющих тестировать WAF, есть даже специальные аккаунты, производящие сбор такого инструментария, например waflib.
Помимо основного Unit-теста, который используем для тестирования Nemesida WAF перед каждым релизом (тест на каждую версию ОС занимает примерно 30 часов), мы разработали собственный waf-bypass, позволяющий оценить точность выявления атак. Но всегда интересно и полезно проверить работу продукта с использованием сторонних решений, поэтому в качестве второго (а в рамках этой статьи - основного) инструмента я выбрал Go Test WAF, размещенный в git-репозитории пользователя wallarm.
Для использования waf-bypass, написанного на Python3, необходимо клонировать проект, установить зависимости и запустить скрипт:
git clone https://github.com/nemesida-waf/waf_bypass.git /opt/waf-bypass/python3 -m pip install -r /opt/waf-bypass/requirements.txtpython3 /opt/waf-bypass/main.py --host='example.com'
Если следовать документации, Go Test WAF можно запускать из докер-контейнера, что я и сделал:
docker build . --force-rm -t gotestwafdocker run gotestwaf --url='http://example.com'
Если проводить сравнение инструментов исходя из их использования, то Go Test WAF работает быстрее (за счет многопоточности) и содержит небольшой набор для проверки False Positive. Учтем это в следующих релизах waf-bypass.
Вижу цель, иду к ней!
Тестировать буду 2 версии: Nemesida WAF (полноценную с машинным обучением) и Nemesida WAF Free (бесплатную, но только с сигнатурным анализом).
Когда увидел результаты тестов WAFВ обзоре Vulners, с которым можно ознакомиться по ссылке, в финальной таблице максимальным результатом WAF, полученным путем тестирования Go Test WAF, являлось значение 83.06%, при этом ModSecurity набрал 49.82%. Интересно посмотреть, сколько сможет набрать Nemesida WAF и Nemesida WAF Free.
Nemesida WAF Free bypass
Напомню, анализ в Nemesida WAF Free производится только сигнатурным методом, при этом эта версия имеет качественно написанную и автоматически обновляемую базу сигнатур (ознакомиться с которой можно по ссылке), а также Личный кабинет (также устанавливается локально) - веб-интерфейс для визуализации событий. Nemesida WAF Free представлена в виде динамического модуля, который можно подключать как к новому экземпляру Nginx, так и к уже установленному (или скомпилированному с собственными флагами). Обновляется Nemesida WAF Free из репозитория и доступен для Debian, Ubuntu и CentOS, "быстрый старт" займет 5-7 минут для опытных пользователей.
Часть содержимого первой страницы Личного кабинета Nemesida WAF FreeЗапускаем Go Test WAF, смотрим результаты.
Nemesida WAF Free: GoTestWAF45.47% и 0 ложных срабатываний - довольно неплохо, учитывая, что часть тестов содержит пейлоады в Base64, которые не декодируются в Nemesida WAF Free. Теперь ловким движением руки и не меняя настроек Nemesida WAF Free, проверим его с помощью waf-bypass:
Nemesida WAF Free: waf-bypass325 пропусков и 1054 заблокированных пейлоадов. Пытаемся запомнить результаты и двигаемся дальше.
Nemesida WAF bypass
Помимо функционала нормализации данных, Nemesida WAF позволяет производить декодирование запросов в различных кодировках, в том числе и в Base64, поэтому было особенно интересно, какой скор он сможет набрать. Начнем с waf-bypass, запускаем, смотрим результаты:
Nemesida WAF: waf-bypass4 пропуска, остальные запросы заблокированы. Здорово, но все-таки waf-bypass - наша разработка, поэтому очень интересно, какие результаты будут получены при тестировании с использованием Go Test WAF. Запускаем Go Test WAF, смотрим результаты:
Nemesida WAF: gotestwafПроверка заняла немного больше времени, но и показатели в 2 раза лучше - 94.45% - то есть на 11.39% выше, чем наилучший результат в обзоре Vulners. Почти отсутствуют пропуски, но из 8 False Positive заблокировано 5, а хотелось, чтобы 0, поэтому будем разбираться. Сперва посмотрим содержимое всех 8 FP-запросов:
- union was a great select- 'h2<h1'- D'or 1st parfume- "1) a-b=c"- john+or@var.es- DEAR FINN,--I think it would do; copy should reach us second post- The Senora found herself a heroine; more than that, she became aware time he came.
Из них ошибочно заблокированные:
- f971e9ace6=union was a great select- 24d85a0990=D'or 1st parfume- 48105a7f77=john+or@var.es- 18196a6191=DEAR FINN,--I think it would do; copy should reach us second post- e7e5421304=The Senora found herself a heroine; more than that, she became aware
Чтобы понять, почему запросы были заблокированы, нужно понимать,
как работает модуль машинного обучения в Nemesida WAF - построение
моделей происходит за счет использования 2-х наборов обучающих
выборок - базы атак и базы условно чистого трафика. Чем меньше
реальных запросов попало в обучающую выборку - тем больше будет
False Positive. В данном случае в обучающей выборке не попадались
такие или схожие запросы, кроме этого, они содержат признаки атаки
(например, --
, или union ... select
, или
'or
), поэтому были заблокированы. Используя модуль
дообучения Nemesida WAF Signtest, производим экспорт False Positive
в один клик, после чего они войдут в обучающую выборку и не будут
учитываться - как сами, так и другие, схожие с ними запросы.
Запускаем тест заново:
Nemesida WAF: gotestwaf (с FP в обучающей выборке)Несмотря на то, что содержимое запросов имеет динамический
контент 24d85a0990
в 24d85a0990=D'or 1st
parfume
, ложные срабатывания отсутствуют, при этом
количество пропусков не изменилось. Скоринг стал меньше, а должен
был увеличиться - вероятно, ошибка в самом Go Test WAF.
Чтобы разобраться в пропусках, я настроил журналирование Nginx таким образом, чтобы фиксировать содержимое запросов, не получивших код ответа 403:
Расширенное журналирование NginxЕсли вы хотите проверить, какие запросы не были заблокированы - активируйте расширенное журналирование в Nginx:
1. В секцию http {}
добавив:
logformat extended '$msec $requesttime $timeiso8601 $timelocal $requestid $status $remoteaddr $scheme $host $request $httphost $httpcookie $httpuseragent $contentlength $contenttype $httporigin $requestbody\n';
и
map $status $loggable { 403 0; default 1; }
2. В секцию server {}
файла виртуального хоста
(например, /etc/nginx/conf.d/1.conf) добавив:
access_log /var/log/nginx/extended_access.log extended
if=$loggable;
После перезапуска Nginx в /var/log/nginx/extended_access.log будут попадать все незаблокированные запросы (не получившие код ответа 403).
Фактически пропусков было всего 3, и об их критичности судите сами:
GET /AEAEAFAEAEAFetcAFpasswd
GET / QUIT /
GET /foo_bar=foo bar=foo[barfoo[bar
Визуализация атак: графики, поиск, отчеты
Вне зависимости от того, используется ли Nemesida WAF или Nemesida WAF Free, к любому из них можно подключить Личный кабинет - веб-интерфейс, позволяющий визуализировать работу модулей:
Личный кабинет: графики и диаграммыЛичный кабинет: графики и диаграммыЛичный кабинет: графики и диаграммыNemesida WAF: информация об атакахВ Личном кабинете есть и другие разделы - информация по атакам методом перебора и SMS-флуде, статистика работы сканера уязвимостей и т.д. Также можно выгрузить общий отчет в формате PDF или CSV. Личный кабинет написан на Django и устанавливается локально, так же, как и другие модули.
И пока на версусе решают, кто из них круче...
Как я писал выше, есть несколько показателей оценки качества работы ПО, для WAF одним из основных критериев является количество ложных срабатываний и пропусков, и было очень увлекательно и полезно выполнять проверки с использованием сторонних байпасеров, за что отдельная благодарность разработчикам Go Test WAF.
Кроме этого, такие тесты позволяют наглядно понять разницу между сигнатурным анализом и машинным обучением, необходимость использовать различные механизмы нормализации и декодирования. Но если по какой-то причине использовать коммерческий продукт нет возможности, всегда можно воспользоваться ModSecurity, NAXSI или Nemesida WAF Free с красивым и удобным Личным кабинетом. Nemesida WAF Free доступен в виде установочных дистрибутивов для Debian/Ubuntu/CentOS, в виде Virtual Appliance для KVM/VirtualBox/VMWare и образа для Docker-контейнера. Больше информации можно найти здесь.
Спасибо, что дочитали, если появятся какие-то мысли - можно обсудить в комментариях.