Злоумышленники могут успешно атаковать 98% веб-приложений. И это не просто громкие цифры, а данные из исследования Positive Technologies. Как такое возможно, если есть инструменты и практики типа SAST, DAST и WAF, а разработчики вроде бы нормально кодят?
Давайте я объясню, как устроены опасные атаки, на примере с разработчиком Василием, который работает в интернет-магазине и которому начальство подкидывает разные ***интересные*** задачки.
Да, забыл представиться — я Артемий Богданов, CHO Start X.
Атака на десериализацию
Сначала немного теории.
Сериализацией называют процесс преобразования состояния объекта в форму, пригодную для сохранения или передачи. Неважно, в какой именно формат преобразуются данные объекта — в двоичный, XML, JSON или даже в обычную текстовую строку. Все это будет сериализацией.
Десериализация — это обратный сериализации процесс восстановления состояния объекта из сохраненных данных. Такими данными может быть полученный по сети поток байтов, параметр HTTP-запроса, введенные в форму данные или информация, прочитанная из файла.
Десериализация может быть реализована как обычный парсинг, в результате которого восстанавливаются поля данных. Такая десериализация не представляет опасности.
Но если помимо данных сохраняются и восстанавливаются еще и метаданные — классы, типы и методы, — то десериализация может создать угрозу. Это происходит в тех случаях, когда сериализованные данные модифицируются, контролируются посторонними или формируются из пользовательского ввода.
В зависимости от приложения злоумышленники могут сконструировать строку данных, которая после десериализации вызовет выполнение произвольного кода на сервере или приведет к другим незапланированным последствиям, например, к обходу системы аутентификации, раскрытию конфиденциальных данных или отказу в обслуживании.
Таким образом, десериализация превращается в источник угроз, как только у злоумышленника появляется возможность добраться до сериализованных данных и изменить их.
Как работает атака на десериализацию
В канун черных пятниц, киберпонедельников и рождественских распродаж к программисту Василию врывается начальник и требует, чтобы он срочно что-то сделал: база данных интернет-магазина работает на пределе. Нужно снизить нагрузку на базу и обеспечить запас мощности, иначе когда новые посетители начнут скупать товары со скидками, сайт просто ляжет.
Василий проанализировал код и придумал, как снизить нагрузку. Для этого он использовал следующий подход:
1. Отказался от хранения состояния корзины пользователя в базе данных. Вместо этого данные корзины сериализуются с помощью pickle и сохраняются в cookie пользователя.
Код на стороне сервера:

2. При каждом запросе данные корзины извлекаются из cookie и десериализуются для использования на сервере.
Код десериализации:

Решение Василия позволило убрать корзины пользователей из базы. В результате и место на сервере экономится, и нагрузка снижается, ведь запросов к базе стало меньше.
Цель вроде бы достигнута, начальник обещает премию, но теперь в приложении появилась уязвимость десериализации. Причина в том, что сохраненные на стороне пользователя данные доступны для изучения и модификации.
Возможные действия злоумышленника
1. Анализ формата данных. Злоумышленник замечает, что данные корзины хранятся в cookie, изучает формат данных и понимает, что они сериализованы с использованием pickle.
2. Создание вредоносного payload. Злоумышленник создает вредоносный объект, который при десериализации выполнит произвольный код, и готовит из него полезную нагрузку (payload) в виде текстовой строки.
Пример вредоносного кода:

3. Подмена cookie. Злоумышленник подменяет cookie с данными корзины на свой вредоносный сериализованный объект.
Теперь, когда пользователь с таким модифицированным cookie посетит сайт, уязвимый сервер десериализует вредоносный объект, в результате чего выполнится произвольный код. В приведенном примере запустится back connect shell — уязвимый сервер подключится к серверу злоумышленника и предоставит ему доступ к консоли shell.
В других языках программирования и при использовании других библиотек сериализации эксплуатация может немного отличаться, но описанные принципы останутся теми же.
Как защититься от атаки на десериализацию
-
Откажитесь от десериализации данных, полученных из ненадежных источников. Это особенно важно для языков и фреймворков, где десериализация может выполнять произвольный код, таких как Python с pickle.
-
Используйте безопасные альтернативы для сериализации. Вместо потенциально опасных методов сериализации, подобных pickle в Python, рассмотрите менее рискованные форматы или методы передачи данных. Возможно, вам вообще не нужна сериализация в классическом смысле, и достаточно сохранить данные в JSON «вручную».
-
Защитите сериализованные данные от модификации с помощью шифрования, подписи или хеширования.
-
Проверяйте и обезвреживайте входные данные перед обработкой. Убедитесь в отсутствии подозрительных элементов, а также в том, что тип и формат данных соответствуют ожидаемым.
-
Используйте принцип наименьших привилегий. Ограничьте доступ и права выполнения кода на сервере, чтобы снизить потенциальный ущерб от вредоносных действий, если уязвимость будет эксплуатироваться.
-
Регулярно обновляйте все используемые библиотеки и фреймворки до последних версий, чтобы воспользоваться исправлениями известных уязвимостей.
Многоликий XSS
XSS (Cross-Site Scripting, межсайтовый скриптинг) — это уязвимости веб-приложений, с помощью которых в страницы сайта можно внедрить вредоносные скрипты. Эти атаки используются для кражи данных, манипуляции контентом веб-страницы или перехвата контроля над аккаунтом пользователя.
Довольно долго считалось, что существует три типа XSS-атак:
-
хранимые (stored),
-
отраженные (reflected),
-
DOM XSS.
Постепенно выяснилось, что вполне реально встретить как хранимые, так и отраженные DOM XSS.
Чтобы исключить путаницу, в середине 2012 года решили, что достаточно двух типов XSS: серверного и клиентского. При этом и серверные и клиентские XSS могут быть как хранимыми, так и отраженными.

Рассмотрим виды XSS-атак подробнее.
Серверный XSS
Серверный XSS возникает, когда данные из ненадежного источника включаются в HTTP-ответ сервера. Источником этих данных может быть пользовательский ввод, переданный с текущим HTTP-запросом, и тогда мы получим отраженный серверный XSS. А если в ответе используются сохраненные на сервере данные, ранее полученные от пользователя, реализуется хранимый серверный XSS.
В этом случае уязвимость находится в коде на стороне сервера, а браузер просто отображает ответ и выполняет содержащийся в ответе скрипт.
Клиентский XSS
Клиентский XSS возникает, когда ненадежные данные используются для обновления DOM с помощью небезопасного вызова JavaScript (например, с помощью innerHTML). Вызов JavaScript считается небезопасным, если его могут использовать для внедрения кода в DOM. Источником данных также может быть запрос или сохраненная информация. Таким образом, возможен как Reflected Client XSS, так и Stored Client XSS.
Хранимые XSS (Stored XSS)
В этом случае внедренный вредоносный скрипт постоянно хранится в базе данных веб-приложения. Сервер выполняет его, когда пользователь посещает сайт. Код JavaScript будет выполняться браузером так же, как он записан в базе данных приложения, поэтому эта атака не требует никаких действий со стороны пользователя.
Отраженные XSS (Reflected XSS)
Отраженные XSS появляются, когда веб-приложение получает от пользователя данные, а в ответ выводит их небезопасным образом. Это может привести к тому, что злоумышленник передаст в браузер код, который будет немедленно исполнен.
Для использования этой разновидности уязвимости злоумышленнику нужно отправить вредоносную ссылку пользователю и убедить его перейти по ней.
Как работают XSS-атаки
Василий еще не получил премию за оптимизацию сайта, а начальник снова на пороге. На этот раз ему понадобились комментарии покупателей к товарам.
Чтобы не усложнять, Василий добавил на страницу с карточкой товара текстовое поле для комментариев. После отправки они отображаются в карточке товара.
Вот как это выглядит в коде:

Василий доволен. Ему удалось быстро выполнить поставленную задачу. Комментарии работают, начальник похвалил, только вот код снова оказался с уязвимостями.
Текст отзыва вставляется непосредственно в HTML без какой-либо обработки и санитизации. Если злоумышленник добавит в отзыв JavaScript-код, он будет встроен в HTML-код страницы и выполнится при отображении отзыва.
Возможные действия злоумышленника
Представим, что злоумышленник вставил следующий JavaScript-код в текстовое поле отзыва:

Вот что будет происходить каждый раз, когда посетитель интернет-магазина откроет карточку товара с этим отзывом:
-
Сохраненный вместе с отзывом скрипт выполнится и добавит на страницу невидимое изображение — HTML-элемент img с src, указывающий на сервер злоумышленника.
-
Все cookies пользователя соберутся и закодируются с помощью encodeURIComponent для корректной передачи на сервер злоумышленника.
-
При загрузке невидимого изображения браузер отправит запрос на сервер злоумышленника и передаст закодированные cookies в параметре запроса.
-
Сервер злоумышленника обработает запрос и извлечет из параметра cookies.
Таким образом злоумышленник будет получать cookie всех покупателей, которые зашли на зараженную страницу товара. Располагая cookie, хакер может зайти на сайт интернет-магазина от имени каждого из этих пользователей и совершить злонамеренное целевое действие, например, изменить адрес доставки пользовательских заказов.
Способы эксплуатации XSS-уязвимости могут меняться в зависимости от настроек сервера, флагов cookie, способа вывода информации и контекста вывода — от того, как именно и куда выводятся пользовательские данные.
Как защититься от XSS-атак
Найти XSS-уязвимость на сайте довольно легко — злоумышленнику достаточно отправлять запросы с вредоносным кодом и анализировать ответ сервера.
А вот устранение XSS часто становится сложным заданием, поскольку требует глубокого понимания контекстов и способов вывода информации в браузер. Именно от этого зависит выбор методов безопасной обработки данных.
Вот ключевые моменты, которые помогут реализовать комплексную защиту от XSS:
-
Контекстно-зависимое кодирование. Кодируйте и экранируйте данные при выводе на страницу в соответствии с контекстом вывода.
-
Валидация. Проводите строгую проверку полученных от пользователей данных, ограничивая их типы и форматы.
-
Флаги Cookies. Используйте флаги HttpOnly и Secure для cookies, чтобы защитить их от доступа через клиентские скрипты и разрешить передачу только через зашифрованные соединения.
-
Content Security Policy (CSP). Настройте CSP, чтобы предотвратить загрузку вредоносных скриптов на ваши страницы, ограничивая источники, с которых можно загружать скрипты.
Сложнее всего разобраться в правильном выборе метода кодирования или экранирования, поэтому давайте вернемся в наш интернет-магазин и поможем Василию разобраться с контекстом вывода информации.

В приведенном коде данные выводятся в теге «p». Это самый распространенный вариант. В данном случае пользовательский ввод необходимо html-кодировать, то есть перевести все обнаруженные в пользовательском вводе спецсимволы в html-сущности.
В php это можно сделать с помощью функции htmlspecialchars:

Теперь, если злоумышленник попробует вставить новый тег, например, <script> — он будет html-кодирован, превратится в <script> и не будет интерпретироваться браузером.
Добавив всего один вызов функции, мы обезопасили интернет-магазин от XSS-уязвимости в комментариях. А вот если бы контекст вывода информации был другой, например, данные выводились в css, как строка в javascript код, либо в url, или если бы они выводились не средствами бэкенда, а через DOM, то стратегия защиты, выбор способа кодирования, экранирования или санитизации были бы другими.
К сожалению, в большинстве фреймворков эти контексты не учитываются, и защита ограничивается html-кодированием. Не рассчитывайте, что использование популярного фреймворка полностью защитит вас от XSS.
Чтение произвольных файлов (Arbitrary File Reading)
Суть этой уязвимости понятна из названия: атакующий может получить доступ к файлам на сервере, которые не должны быть доступны для чтения через веб-приложение. Это могут быть, например, системные и конфигурационные файлы, файлы баз данных, исходные коды приложения и другая чувствительная информация.
Как происходит чтение произвольных файлов
Практически всегда возможность чтения произвольных файлов появляется, когда права доступа к файлам и директориям настроены некорректно, а для обращения к ним используется пользовательский ввод, который никак не валидируется.
Вернемся к Василию и посмотрим, как проявляется эта уязвимость. Он как раз получил очередное задание от начальника — сделать, чтобы покупатели могли просматривать электронные счета-фактуры своих заказов.
Вот что сделал Василий:
Документы генерируются в формате PDF и сохраняются в специальной директории на сервере. Для просмотра счета-фактуры нужно перейти по ссылке:
https://super-shop.ru/download_invoice.php?invoice_id=123
Код для скачивания счета-фактуры выглядит следующим образом:

Все работает, счета-фактуры отображаются, но в интернет-магазине появилась новая уязвимость.
Возможные действия злоумышленника
Значение параметра invoice_id конкатенируется с путем к файлу, но при этом не проводится никакой проверки или санитизации этого параметра. Это позволяет злоумышленнику манипулировать параметром invoice_id для доступа к любым файлам на сервере.
Например, злоумышленник может изменить URL вот так:
https://super-shop.ru/download_invoice.php?invoice_id=../../config.php
или так
https://super-shop.ru/download_invoice.php?invoice_id=../../../../../../etc/passwd
В ответ на эти запросы злоумышленник получит содержимое файла конфигурации config.php, в котором могут содержаться пароли базы данных, или увидит список пользователей сервера, хранящийся в файле /etc/passwd.
Как защититься от чтения произвольных файлов
-
Проверяйте пользовательский ввод, чтобы предотвратить нежелательные запросы к файлам. Проверяйте допустимость имен файлов, ограничивайте символы, проверяйте пути.
-
Используйте безопасные методы доступа к файлам. Вместо прямого формирования пути к файлу, используйте безопасные методы для доступа к файлам или используйте специализированные библиотеки.
-
Убедитесь, что ваше приложение или сервис работает с минимально необходимыми правами.
-
Разделите приложения и их данные, чтобы предотвратить утечку информации между различными частями системы.
-
Настройте системы мониторинга, чтобы отслеживать необычные или подозрительные действия. Это может помочь обнаружить атаку и вовремя на нее среагировать.
-
Обучите разработчиков принципам написания безопасного кода, чтобы уменьшить вероятность ошибок, приводящих к уязвимостям.
Выводы
Не существует универсального способа разом решить все проблемы с помощью одного простого действия. Если кто-то утверждает, что система защиты A или фреймворк B сделают ваше приложение абсолютно неуязвимым, скорее всего, он чего-то не знает, недоговаривает или банально пытается вас обмануть.
По моему опыту наибольший эффект дает фокус на процессах и людях.
Фокус на процессах означает, что безопасность должна не просто присутствовать в компании в виде отдельного подразделения, а стать обязательной частью процесса разработки. Это позволит внедрять требования к безопасности на этапе разработки продуктов — при проектировании, выборе архитектуры и технологического стека.
Для этого нужно, чтобы сотрудники отдела безопасности занимались не формальным контролем разработки, а полноценно участвовали в написании кода, анализировали инфраструктурные проблемы, следили за тестированием и отчетами статических и динамических анализаторов кода, консультировали программистов и помогали устранять выявленные уязвимости.
Фокус на людях означает, что руководство продуктовой команды осознает: ключевые аспекты в написании безопасного кода — это понимание основ безопасности, осведомленность о распространенных уязвимостях и методиках их предотвращения.
Для этого требуются инвестиции в обучение разработчиков, но в долгосрочной перспективе это помогает минимизировать риски и, самое главное, экономить деньги компании. Ведь исправление багов после релиза стоит дорого и тратит ресурсы разработки.
Я помогаю разрабатывать курсы и практические задания на платформе Start EDU. Мы сделали ее, чтобы научить разработчиков писать безопасные программы. Если вам интересно, можете запросить демо и посмотреть, как у нас все устроено:)
ссылка на оригинал статьи https://habr.com/ru/articles/787176/
Добавить комментарий