Источник: Nuances of Programming
TL;DR
В январе 2019 года мы запустили инструмент, который эффективно находит уязвимости в Python-коде. Мы создали автоматизированную систему, в которой объединили алгоритмы анализа потока данных с новым ML-компонентом. Таким образом, наш инструмент находит гораздо больше уязвимостей, чем другие, традиционные инструменты. Запустив его в нескольких репозиториях с открытым исходным кодом, мы нашли и сообщили о 35 критических угрозах безопасности из списка OWASP Top Ten. На скриншоте показана одна из угроз:
Неуклонно растет интерес к безопасности веб-приложений. Одновременно с этим, растет интерес к уязвимостям со стороны злоумышленников. В таких условиях разработчикам становится сложнее работать, однако инструменты для автоматической проверки кода должны облегчить ситуацию. Именно поэтому мы решили улучшить алгоритмы автоматического поиска уязвимостей. И сейчас мы расскажем, как нам это удалось.
Самый распространенный метод анализа кода называется taint-анализ: он помогает обнаружить такие уязвимости, как межсайтовый скриптинг (XSS), внедрение SQL-кода (SQLi), обход каталога (PT), удаленное выполнение кода (RCE) и т. д. Мне кажется, что популярность taint-анализа связана с простотой его основной идеи: «чтобы сделать код безопасным, сначала нужно убедиться, что экранирование пользовательского ввода прошло успешно».
Возьмем для примера этот сверхсложный фрагмент кода:
from django.http import HttpResponse
def hello(request):
name = request.GET.get("name")
return HttpResponse("Hello " + name)
Здесь пользовательский ввод из HTTP-запроса попадает в имя переменной name, а затем в вызов django.http.HttpResponse.Поэтому, если я добавлю скрипт <script>evil_code</script, то evil_code начнет выполняться в браузере жертвы. Если вы все еще не поняли, как это работает, то вот неофициальное краткое описание этого метода.
При taint-анализе выделяют три категории объектов (переменных, вызовов функций и т. д.):
- Sources (источники)— содержат введенную пользователем информацию (например, request.GET.get(“name”));
- Sanitizers (санитайзеры) — обрабатывают небезопасную введенную пользователем информацию, превращают ее в безопасную (например, django.utils.html.escape());
- Sinks (накопители данных)— запускают уязвимость, если злоумышленнику удастся ввести данные (например, django.http.HttpResponse()).
Главная цель анализа—убедиться, что все введенные пользователем данные пройдут через санитайзеры на пути из источника в накопитель. Каждый поток данных, не прошедший через санитайзеры, считается потенциальной уязвимостью.
К сожалению, taint-анализ зависит от спецификации: списка всех источников, накопителей данных и санитайзеров. Чтобы вручную составить такую спецификацию, нужен «эксперт по безопасности», который должен разбираться и в базе исходного кода проекта, и во всех используемых сторонних средах. В идеале «эксперт по безопасности» должен составить список всех источников, накопителей и санитайзеров, присутствующие в коде, и запустить инструмент taint-анализа. Довольно очевидно, что у этого подхода есть некоторые недостатки.
Во-первых, представьте, насколько сложно вручную собрать такую спецификацию: нужно просмотреть тонну документации и кода, как проекта, так и фреймворков. А теперь вспомните знаменитую цитату Ларри Уолла: «Лень и нетерпеливость — это истинные добродетели великого программиста», и почувствуйте жалость к бедняге, которому поручили такое задание.
Во-вторых, каждый упущенный элемент в спецификации станет потенциально игнорируемой уязвимостью. Люди часто ошибаются, особенно когда занимаются рутинной работой, такой как эта. Можно ли с уверенностью сказать, что составленный список будет полным?
В-третьих, это не разовое событие. Составленный список нужно переделывать и дополнять каждый раз, когда обновляется инфраструктура или в код вносятся значительные изменения. Это намного увеличивает стоимость обслуживания проекта.
В-четвертых, этот подход не масштабируется. Каждый проект и каждая инфраструктура уникальны: получившиеся спецификации безопасности не получится использовать повторно на 100%.
Эти четыре недостатка также означают, что в этом случае не получится эффективно использовать такой распространенный инструмент, как Code Review. Более того, консультантов по безопасности слишком мало, их не хватит на все проекты.
Мы решили эту проблему с помощью DeepCode и открытого исходного кода. Мы создали инструмент, который анализирует выложенный в открытый доступ код, собирает статистику обо всех API, объединяет их в единую модель и автоматически составляет список новых источников, накопителей и санитайзеров. Он также анализирует, какие именно уязвимости чаще всего встречаются в накопителях определенного типа. На основе этого анализа он предлагает санитайзер, который поможет справиться с этой проблемой.
Очевидно, что разработанный нами подход устраняет первый, третий и четвертый недостаток. Но что насчет второго? Мы провели экспериментальный поиск ошибок. С помощью нашего инструмента (выложен в открытый доступ) мы изучили репозитории с открытым исходным кодом на GitHub. Мы специально выбирали веб-приложения, которые используются (или будут использоваться) множеством людей (в том числе, злоумышленниками).
Результатом этого эксперимента стал список обнаруженных и исправленных уязвимостей. Более того, мы доказали, что наш инструмент находит интересные, нетривиальные и неожиданные ошибки.
Читайте нас в телеграмме и vk
Перевод статьи Victor Chibotaru: Meet the tool that automatically infers security vulnerabilities in Python code