Pull to refresh

Comments 17

«Нахождение сложных уязвимостей – экспоненциально сложная задача» — разве это само по себе не является признаком smelly code?
В смысле, разработчику ведь для понимания тоже придётся прослеживать все пути — значит, надо где-то их разорвать, воткнув по дороге какой-то контракт. Чтобы статическому анализатору достаточно было проверить выполнение контракта, а не весь путь.
В некоторых случаях, действительно, разработчик может так сделать (использовать привязку параметров в SQL-запросе, например), и анализатору станет проще. Однако мы говорим про анализ случайного кода. Если анализатор будет просто проверять невыполнение контракта, на любом реальном проекте нормального размера будут сотни тысяч «уязвимостей», этим будет нереально пользоваться.
Ну, кодовую базу ведь надо потихоньку приводить к читаемому виду :-). Так что, может, увидеть среди прочего диагностику «хозяин, я тут уже два часа пытаюсь прочитать твой код, а что он вообще делает?» может оказаться не худшим вариантом :-)

Что касается «просто проверять выполнение контракта» — вы меня не поняли. Идея в том, что если контракт написан — нужно проверить, выполняет ли его одна сторона, и если да — проверка для второй резко упрощается, достаточно просмотреть лишь пути для выполненного контракта. И это не ослабляет проверку, а ужесточает её: мы проверим и общую корректность, и выполнение контракта.
А можете поделиться опытом чуть более детально?

  1. Что вы делаете с критическими уязвимостями в библиотеках?

    Казалось бы, шансов на то, что злоумышленник тоже проанализировал библиотеку и массово ищет ее уязвимости в вашем проекте (вариант — по всем сайтам в интернете) намного больше, чем на поиск уникальных уязвимостей. Выходит, одна такая оставленная уязвимость практически множит на ноль все остальные усилия по повышению безопасности?
  2. Какие анализаторы из тех, что вы использовали в своей практике можете посоветовать как максимально простые во внедрении?

    Для всех технологий, где вам удалось внедрить анализатор в не академический проект и не выкинуть его в течение пары-тройки месяцев.
  1. Оценка опасности уязвимости. Если не опасная, то можно проигнорировать (но так лучше не делать). Если опасная, то либо обновлять библиотеку (если там уже поправили), либо патчить зависимость самим ( и желательно патч в апстрим заслать).


  2. Зависит от используемой Вами технологии.


Зависит от используемой Вами технологии.

Ну, меня много технологий интересует :)

.NET
.NET Core
Ruby on Rails
Elixir
Android — Java & Kotlin
JavaScript (Node.js, React, React Native)
C/C++ — Windows, Linux

Я сам пытался несколько раз, но всегда застревал на этапе «я уже 3 дня этим занимаюсь, а исправил/внимательно посмотрел только 10-15% от общего объема, из просмотренного половину исправить не могу, а заказчик требует новых фич».

Собственно, просьба поделиться опытом именно практического внедрения, у кого оно состоялось хоть куда-нибудь. Без общих слов, только хардкор — анализатор, технология, размер проекта в Мб/KLoc, время внедрения в вашем случае в человеко-месяцах, как долго использовалась (используется).
Например, в PVS-Studio есть технология Mass Suppression. Она позволяет разметить все сообщения, которые выдает анализатор, как «неинтересные». И при следующем прогоне анализа будет выдано 0 сообщений. Далее даже полный прогон анализатора будет выдавать сообщения только на новый или на модифицированный старый код.

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

Их надо править постепенно, планово выделяя на это время.

Вам хочется цифр и конкретики. ОК, я лично участвовал во внедрении анализатора в C++ проект размером 8 млн строк кода. При первом запуске там было порядка 5 000 сообщений от анализатора уровней High и Medium («совсем страшно» и «страшновато»). Сообщения уровня Low («скорее всего не ошибка, но мало ли») игнорировались и не правились. Полный прогон такого проекта в PVS-Studio занимал 6 часов.

Все 5 000 ошибок были сначала подавлены как «неинтересные», и разработчики смогли получать уведомления только о новых ошибках. И сразу их править. На эти оставшиеся 5 000 ошибок была выделена команда 3-5 человек, которая победила их за 3-4 месяца. Цифры немного плавающие, так как кроме этого были все же и другие задачи с разной интенсивностью для этой команды, но в целом порядок оценить можно довольно точно.
Последнее время мы внедряем только наш анализатор, так что я предвзят:) Но пока заказчики не выкидывали его, все внедрения были успешные.
Внедрения очень разные, от ручного использования раз в месяц до интеграции в CI.

Из первого: мобильные приложения iOS и Android (два приложения, средние по размеру), заказчик примерно раз в месяц сканирует приложение по ссылке на Google Play и AppStore, ранжирует уязвимости, используя функционал инструмента, передает разработчикам уже финальный отчет для исправления.

Из второго: Java, 4.5 млн LOC, запуск из Jenkins раз в сутки. Внедрение шло 2 месяца, но в основном это связано с тем, что нужно было наладить организационный процесс (взаимодействие подразделений по использованию инструмента).

Думаю, мы напишем отдельную статью про опыт внедрения.
Есть опыт внедрения Fortify, серия больших проектов.
Оценить время внедрения сложно. У нас парочка «волонтеров» настроили билды для всей фирмы, прогоняется раз в неделю. Для самого большого моего проекта (1 млн LOC) анализ занимает 1 час (в самом начале занимал около 8 часов, я не знаю что и как оптимизировали).
Мои затраты были наверное около пары недель чистого времени. В самом начале надо разобраться, понять в чём суть уязвимостей, как их чинить. Потом разгребается всё весьма быстро, много однотипных вещей, которые можно одной строчкой поправить или вообще отклонить.
Что важно — четкая позиция менеджмента «к такой дате ни одного critical или high». Тогда это работает. Уже пару проектов почистил полностью, еще немного осталось. Опять таки у нас регулярно проходит аудит безопасности, и пен-тестеры временами находили дырки, уже найденные Fortify — сильно мотивирует.
Medium и Low больше похожи на «плохие практики» чем реальные проблемы, так что просматриваю но не стремлюсь закрывать.
Весьма важна интеграция с багтрекером. Очевидно, что практически везде можно создавать баги, но Fortify умеет их закрывать или переоткрывать по результатам следующего прогона.
Ещё важна поддержка от вендора. У нас вообще есть отдельный проект на котором пробуем разные «ошибки», удобно сразу постить баги. Этакий юнит тест для анализатора :) за последний год они поправили очень много ошибок, ушло очень много false positive. Хотя до сих пор ловит все null propagation (?.) как Possible Null Reference.
У себя в подразделении (мобильная разработка, java + kotlin), использовал SonarQube.
Изначально тестировали анализ по команде из Студии (gradle-task), когда обкатали, встроили в основной процесс — анализ происходит на этапе сборки приложений в TeamCity.
Сборку реально пока не блокирует, только алармит всем заинтересованным о найденных проблемах.
Когда вычистим весь код, сделаем негативный результат анализа блокирующим для продолжения сборки.

Ориентировочные объемы:
30 проектов, суммарно 203 тыс. строк кода.

А как анализатор может найти уязвимости в библиотеках? Они же бинарники. А если они с исходным кодом, то что мешает их исправлять?
Библиотеки довольно часто используются в исходниках. И да, можно там что-то поправить. Но если обновляется библиотека, то либо надо тянуть свои правки в новую версию, либо пытаться понять, нужны ли они в новой версии. Конечно это довольно сложно и в целом люди забивают на правки исходников чужих библиотек, если это хоть сколько-то возможно сделать.

Разным анализаторам нужно разное. Кто-то работает на исходном коде (или, например, на AST, который сам же строит по исходному коду), а кому-то «достаточно» бинарника (в кавычках, потому что это не обязательно меньшее требование — как описано в статье, собрать исходники может быть не так тривиально). Это может быть или совсем «нативный» бинарник (например, для C/C++), или набор class-файлов для Java/Kotlin/Scala — и class-файлы, кстати, во многом сохраняют семантику исходного кода, в большей степени, чем «совсем бинарники».


С бинарниками ещё возникает сложность с тем, чтобы найденную уязвимость пользователю отобразить — нельзя же написать, что «в библиотеке Foo есть SQL-инъекция». Более крутые анализаторы способны декомпилировать бинарник и сопоставить место, где нашли в нём уязвимость, строчке в декомпилированном коде.


А если они с исходным кодом, то что мешает их исправлять?

Может быть, их исходный код и доступен (в публичном репозитории), но чтобы внести туда свои правки, нужно делать форк, pull request, ждать следующего релиза и т.д. Альтернативно, можно, конечно, собирать проект со своей копией библиотеки, а не пытаться исправить уязвимость в upstream'е, но это много другой головной боли.

Как правильно написано выше, анализатор может работать и на бинарниках, как, собственно, наш анализатор.
Про это мы немного писали в блоге, например про байткод Java и анализа iOS-приложений (раз и два).
«Пример я приводил в начале статьи: SQL-инъекцию никогда не найдешь без алгоритмов анализа потока данных.»
Отсутствие инъекций вполне можно доказать системой типов. На уровне типов можно различать пришедшие снаружи строки и строки, прошедшие обработку, необходимую для помещения в запрос. Или можно генерировать запросы с помощью DSL (LINQ, Slick).
Генерировать SQL-запросы, действительно, можно так, чтобы проверить отсутствие SQL-инъекции было просто. Проблема в том, что существует очень много кода, написанного по-другому. И его надо анализировать.

Да, можно и нужно использовать систему типов для таких вещей. Проблема в том, что это решение принимает разработчик библиотеки для работы с БД, а не автор конченой программы (и тем более не анализатор). И в случае JDBC, например, запросы передаются в виде String sql.


Так что конечно было бы лучше, если бы все использовали систему типов, но анализатор всё равно должен уметь находить SQL-инъекции в коде, который использует «сырые» строки.

Sign up to leave a comment.