Сегодня у нас не совсем обычная статья. Как следует из заголовка, она посвящена проблемам непрерывной защиты веб-приложений и разбита на две части, отражающие два взгляда на проблему: с позиции разработчиков WAF (Андрей Петухов, SolidLab) и с точки зрения центра мониторинга и противодействия кибератакам, который использует WAF для оказания сервиса клиентам (@avpavlov, Solar JSOC).
Начнем мы с разработчиков, а через неделю дадим слово эксплуатантам WAF.
Мы из SolidLab. Наша основная экспертиза – это application security во всех проявлениях – offensive (анализ защищенности приложений, инфраструктур, процессов) и defensive (построение SDLC и отдельные аспекты этого – например, ручной анализ кода, обучающие курсы и семинары, внедрение средств защиты вообще и нашего WAF в частности).
Для начала мы хотели бы поговорить о тенденциях в мире разработки и эксплуатации веб-приложений, которые определяют ландшафт угроз и методы защиты. Полагаем, что рассуждения о SOC, непрерывном мониторинге и WAF’ах скоро будут неотделимы от рассуждений о непрерывной разработке и особенностях этого процесса для того или иного приложения/сервиса. Начнем с очевидной тенденции к сокращению длительности релизного цикла. Интересные факты:
- Тенденция на уменьшение релизного цикла ПО именно как новый тренд отмечалась еще в 2001 году в статье Microsoft Research (визионеры?).
- Статья о Continuous delivery в Википедии появилась в декабре 2011 года.
- В 2014 году появилась Continuous Delivery Conference.
- В последние 5 лет массово появляются научные статьи (см. Google Scholar) по изучению наблюдаемых феноменов (например, “Continuous Software Engineering and Beyond: Trends and Challenges”) с анализом собственного опыта (например, “Continuous delivery? easy! just change everything (well, maybe it is not that easy)”).
Короткие релизные циклы приводят к переосмыслению причин и мотивов, которые делали целесообразным использование традиционных мероприятий – привлечение внешних консультантов для поиска недостатков (неважно, каким методом – «белым» или «черным» ящиком), ручное тестирование собственной QA- или security-командой: схема «проверил код релиза и живи полгода спокойно до следующего» больше не работает. В разработке с короткими релизными циклами перечисленные «традиционные» мероприятия рассматриваются уже более зрело: как источник обратной связи на процессы и их обеспечение всем необходимым – инструментами, людьми, методиками, а не как способ получить некоторое защищенное состояние приложения и зафиксировать его.
Отметим, что непрерывность процессов (особенно в части тестирования и развертывания) подразумевает переход к высокой степени автоматизации рутинных задач. Автоматизация отлично помогает снизить частоту попадания в продукт типичных (понятных для всех участников разработки) недостатков:
- Недостатков, под которые написали тесты.
- Недостатков, под которые написали правила для статического/динамического анализатора.
- Недостатков, которые являются следствием человеческого фактора (автоматическая подготовка окружения, конфигурация и развертывание): вероятность их привнесения минимизируется за счет автоматизации и грамотного управления изменениями в тех самых скриптах автоматизации.
Тут же заметим, что решение рутинных задач современные веб-платформы и фреймворки (RoR, Django, Spring, Struts, ASP.NET MVC и т.п.) стараются забирать на себя, не давая шанса разработчикам выстрелить себе в ногу, реализовав, например, собственную защиту от CSRF или шаблонизатор на основе find/replace. Соответственно, по мере адаптации новых веб-платформ в перспективе можно ожидать снижение вероятности привнесения в код недостатков, позволяющих проводить атаки типа CSRF, SQL injection, XSS. Что уж говорить, даже большинство XML-парсеров сегодня по умолчанию запрещают разрешение внешних сущностей (т.е. применяют принцип safe defaults).
Не такой прямолинейной с идейной точки зрения оказывается тактика борьбы с недостатками других типов:
- Нетипичные недостатки уровня логики в отдельных модулях (функции, которые не может забрать на себя веб-платформа). Например, недостатки, связанные с некорректной/недостаточной авторизацией при доступе к объектам (англ. Indirect Object Reference).
- Недостатки, появляющиеся на стыке ответственности различных групп: например, разработчиков различных сервисов в микросервисной архитектуре, возникающие в отсутствие явных контрактов, или администраторов и devops’ов). Примерами являются недостатки, связанные с импортом или загрузкой файлов (англ. Insecure File Upload), а также недостатки, связанные с некорректной интеграцией (например, SSO, платежной системы, облачного чата).
- Недостатки, связанные с использованием 3rd-party библиотек/платформ/фреймворков с опубликованными уязвимостями. Рассуждения касаются в том числе и бинарных библиотек, обертки над которыми использует приложение, и утилит, которые запускаются как отдельные процессы (ярким примером будут уязвимости в ImageMagic – CVE-2016-3714, CVE-2016-3715, CVE-2016-3716, CVE-2016-3717, CVE-2016-3718) или ffmpeg. Важность своевременной защиты от атак на недостатки в 3rd-party-компонентах трудно переоценить. В 2017 году практическая реализуемость массовых автоматизированных атак в масштабах всего Интернета не вызывает вопросов. Примерами служат недавние набеги на Joomla (например, CVE-2016-8870 + CVE-2016-8869) или Apache Struts (CVE-2017-5638).
Для полноты изложения важно упомянуть о вариантах решения перечисленных задач в рамках sSDLC методами, альтернативными от мониторинга.
От нетипичных недостатков можно избавляться через whateverbox-анализ от сторонней организации, проводимый с определенной периодичностью, или через массовое народное непрерывное тестирование aka Bug Bounty. Недостатки третьего типа на этапе сборки можно устранять, реализовав анализ внешних зависимостей (см. Vulners, WhiteSource, OWASP dependency-check), а на этапе эксплуатации – выполнением тех же проверок теми же инструментами, но в виде отдельного задания и с большей частотой. Мы же с коллегами больше будем говорить про защиту от атак через непрерывный мониторинг и реагирование.
С точки зрения управления процессом разработки параметры защищенности создаваемого ПО/сервиса – целевые показатели, подлежащие планированию. Тактика достижения этих показателей, по-хорошему, определяется на этапе инициализации проекта (или на этапе его реформирования) и зависит от модели угроз и оценки рисков, ограничений (бюджетных, временных и других), доступных производственных ресурсов (квалификация, методическое обеспечение) и так далее. Наше видение заключается в том, что правильно организованный мониторинг веб-приложения на этапе эксплуатации обеспечит не только снижение рисков, связанных с реализацией угроз через недостатки веб-приложения и его окружение (что очевидно), но и снижение рисков, связанных с неправильными управленческими решениями, которые принимаются в процессе разработки, или ненадлежащей реализацией хороших и правильных решений.
Другими словами, наличие правильного мониторинга увеличивает число степеней свободы при определении тактики достижения параметров защищенности создаваемого ПО/сервиса на начальном этапе.
Из рассуждений выше видно, что среди прочих, правильный мониторинг должен решать следующие ключевые задачи защиты веб-приложений:
- Оперативная защита от 1-day атак на компоненты приложения. Цель – предотвратить атаку на 1-day уязвимость (а желательно и на 0-day) в том случае, если по каким-то причинам атака пришла раньше обновления.
- Адаптация к постоянным изменениям приложения (как функциональным, так и технологическим). Цель – в каждый момент времени иметь возможность эффективного контроля взаимодействий клиентов с измененными аспектами приложения (видеть атаки, иметь возможность гранулярной блокировки, иметь возможность гранулярной настройки).
- Обнаружение логических атак на приложение. Цель – минимизировать последствия от нетипичных (логических) ошибок, которые попадают в прод. Рационально исходить из предположения, что такие ошибки практически невозможно полностью устранить автоматизированными процедурами в рамках sSDLC, а, следовательно, работающих варианта остается два: Bug Bounty и мониторинг с реагированием.
Помимо перечисленных задач, которые, по нашему мнению, должны решаться правильным мониторингом (и любым WAF’ом как основным инструментом для построения такого процесса), мы еще предлагаем список архиважных фич для WAF'ов.
В отличие от задачи сравнения WAF’ов вообще (по функциональным критериям или критериям производительности) и разговоре об эффективности вообще (еще не один benchmark WAF’ов не был признан сообществом, все были прилично раскритикованы), мы хотим обратить внимание на свойства инструментов, которые позволят оценить, подходит ли данный инструмент для защиты конкретного приложения. Постановка задачи именно такая – оценить применимость WAF для конкретного приложения на конкретном стеке технологий.
WAF должен понимать прикладной протокол защищаемого приложения
Здесь действует простое правило: если WAF не сможет разобрать, каким образом передаются значения параметров, он не сможет обнаружить и манипуляции с этими значениями (injection/tampering).
Под прикладным протоколом приложения мы понимаем:
- Способ адресации функций/ресурсов приложения. В самых простых приложениях это часть PATH в URL. Иногда встречаются приложения, где URL-путь всегда одинаковый (например, /do), функции адресуются значением параметра типа “action”, а ресурсы – параметром типа “page” или “res”. В общем же случае функция/ресурс может адресоваться произвольным набором атрибутов HTTP-запроса.
- Способ передачи входных параметров, которые параметризуют функции приложения. Отметим, что спецификация протокола HTTP никак не ограничивает фантазию веб-разработчиков в выборе способа транспорта необходимых данных через структуру HTTP-запроса.
Таким образом, разбор протокола защищаемого приложения WAF’ом – это определение по каждому HTTP-запросу, какая функция приложения вызывается или какой ресурс запрашивается, с какими параметрами и от чьего имени, если речь идет о закрытой зоне приложения, доступной после аутентификации.
В качестве примера интересных протоколов передачи параметров можно привести следующие:
- 3D-Secure. На одном из шагов протокола инкапсуляция выглядит следующим образом: на сервер приходит POST-запрос с типом контента application/x-www-form-urlencoded, в теле запроса есть параметр PaReq. Параметр PaReq является XML-документом, сжатым при помощи алгоритма DEFLATE, затем закодированного в Base64 и URL-кодированного. Соответственно, реальные параметры приложения передаются в тегах и атрибутах этого XML-документа. Если WAF не может раскрыть такую «матрешку» и применить политики анализа к параметрам внутри XML (и/или валидировать его структуру), значит WAF по сути работает в режиме Fail Open. Другие примеры из этой же серии – это многочисленные XML в JSON и наоборот, конечно, не без помощи упаковки в BASE64.
- Google Web Toolkit и другие протоколы, использующие собственную сериализацию (не JSON/XML/YAML/...). Вместо тысячи слов – один пример запроса:
Соответственно, если WAF не может получить из запроса конечные значения параметров, с которыми оперирует защищаемое приложение, то WAF не работает. Отметим, что существует приличное количество способов сериализации бинарных объектов (а еще можно запилить свой собственный!).
- Oracle Application Express (APEX). URL приложения в APEX выглядят примерно так:
http://apex.app:8090/apex/f?p=30:180:3426793174520701::::P180_ARTICLE_ID:5024
POST-запросы в URL-части – аналогично, а параметры передаются в теле (x-www-urlencoded), но названия вне зависимости от вызываемой операции – одинаковые: x01=val1&x02=val2… и т.п. Вот пример запроса:
Если в первых двух примерах разбор протокола требовался для определения значений входных параметров, то в приложениях такого типа WAF дополнительно должен понять, какая запрашивается операция или ресурс. Заметим, что никто не мешает разработчикам приложений на APEX в параметрах x01, x02,… передавать, например, XML/JSON, закодированный в base64, или, как на последнем снимке, сериализованные X-WWW-URLENCODED параметры.
WAF должен иметь гранулярность уровня операций защищаемого приложения
Приложения на APEX отлично иллюстрируют следующий тезис: WAF должен применять свои механизмы/политики/правила не с гранулярностью сущностей HTTP-протокола (секции URL, заголовки и их значения, имена параметров и их значения), а с гранулярностью функций приложения и их входных параметров.
Действительно, для приложения на APEX параметры x01, x02 и т.п. будут являться транспортом значений для всех его функций, но:
- Инкапсуляция значений этих параметров может быть разной (см. значения x01 на снимках экрана выше).
- Как следствие, типы, области значений и семантика этих параметров для каждой функции приложения будут тоже отличаться.
Получается, что от механизмов WAF мы хотим следующего:
- Подсистема построения и применения позитивных моделей должна строить не одну общую позитивную модель на основе всех наблюдаемых значений параметра x01, а N моделей по числу функций приложения, принимающих этот параметр.
- Подсистема сигнатурного анализа должна применять к параметру x01 не один и тот же набор сигнатур, а K наборов (К<N) в зависимости от пожеланий оператора по покрытию сигнатурами значений x01 для действий или их групп.
- Если же оператор захочет настроить для параметра x01 какое-то дополнительное правило (например, подавление ложного срабатывания), то он должен иметь возможность выбирать scope работы этого правила не в терминах протокола HTTP (регулярное выражение над URL, к примеру), а опять же в терминах функций приложения, принимающих x01 (например, в функции регистрации применять, а в функции сброса пароля — нет).
Авторы данной статьи встречались с ситуацией, когда на WAF одного крупного вендора не работал User Tracking[1] на APEX-приложении как раз из-за того, что правила для разделения успешного login-действия, неуспешного login-действия, logout-действия и остальных действий невозможно было задать предоставляемыми выразительными средствами — это были регулярные выражения над полями HTTP-запроса.
Приведенные рассуждения справедливы, конечно, не только для APEX-приложений, но и для различных приложений со сложной маршрутизацией не на основе URL: XML-RPC, JSON-RPC, SOAP и т.п.
WAF должен иметь возможность задания политик на уровне операций и объектов защищаемого приложения
Не секрет, что основными способами обнаружения атак на веб-приложения являются синтаксический анализ для обнаружения синтаксических аномалий (соответствует injection-атакам) и статистический анализ для обнаружения аномалий, связанных со слишком большим количеством запросов (подбор паролей/токенов/OTP, дирбастинг, перечисление объектов приложения – например, существующих пользователей, умный DoS и так далее). Намного сложнее ловятся атаки, которые не вызывают синтаксических или статистических аномалий – типичным примером будет запрос чужих объектов (англ. Insecure Direct Object Reference). Такие атаки часто еще называют «логическими» или атаками на бизнес-логику.
Возникает справедливый вопрос – на каком уровне абстракции происходят аномалии при атаках такого типа?
Мы считаем, что аномалии, возникающие при атаках на бизнес-логику – это аномалии уровня операций и объектов защищаемого приложения, для чего требуется понимать сценарии использования приложения, жизненный цикл и принадлежность его объектов пользователям приложения, вычислять зависимости по данным и по объектам между отдельными шагами одного сценария использования или между различными сценариями использования, можно выявить аномалии, возникающие при атаках на уровне логики.
На наш взгляд, перспективой развития WAF’ов как инструментов мониторинга является именно понимание уровня предметной области приложений, работа на уровне операций и объектов, построение между ними зависимостей и, как следствие, обнаружение атак на логику сценариев в этой предметной области.
- Механизм User Tracking позволяет связать запросы, отправляемые пользователями приложения после аутентификации, с их логинами. Для конфигурации этого механизма инструменты обычно требуют ввести критерии успешного логина, неуспешного логина и критерии инвалидации сессии (тайм-аут по бездействию при наличии, новый вход под тем же пользователем, отправка logout-запроса по заданному URL и т.п.).
Автор: SolarSecurity