Рубрика:
Спецпроект «Базальт СПО». Развитие Open Source в России
|
Facebook
Мой мир
Вконтакте
Одноклассники
Google+
|
Николай Костригин: «Мы создали Hantis, конвейер автоматизации. Проекты, исследуемые разными инструментами, переходят от одного исполнителя к другому, развиваются, возвращаются к автору, и так по кругу»
О том, как идет работа по повышению безопасности отечественного программного обеспечения, рассказывает руководитель направления РБПО «Базальт СПО».
– В декабре 2024 года на Открытой конференции ИСП РАН вы получили награду в номинации «Лучшая командная работа по статическому анализу» от ФСТЭК России и Центра исследований безопасности системного ПО ИСП РАН. Расскажите об этой награде и о вашей команде.
– С 2021 года при координации со стороны Института системного программирования РАН ведется работа по проверке свободного программного кода. В деятельности Консорциума сейчас участвуют более 60 организаций – это и институты, и коммерческие компании. Мы подключились с самого начала.
Всё это делается с целью повышения доверия к программным компонентам, которые в мировом сообществе признаны критическими.
Награждение в 2024 году происходило впервые, это подведение первых итогов деятельности Консорциума.
– Кто входит в Консорциум и какую он роль играет в обеспечении безопасности ПО?
– Основная роль Консорциума – организационная, координационная. Через Консорциум распределяются задачи, можно отслеживать, чтобы не было дублирования, когда мы что-то проверяем по собственной инициативе. Также Консорциум накапливает и систематизирует экспертизу в области проведения исследований. Она становится доступной участникам при присоединении.
Работа по повышению безопасности отечественного ПО строится на совместных исследованиях, обмене результатами анализа, доработке и освоении новых инструментов выявления уязвимостей.
Чтобы дать собеседнику представление о масштабах проблемы, лежащей перед исследователями безопасности ПО, довольно часто прибегаю к количественному описанию GNU/Linux дистрибутива: в репозиторий свободного ПО входят десятки тысяч бинарных пакетов. В дистрибутиве, который включает около двух-трех тысяч пакетов, на поверхности атаки оказываются десятки пакетов.
Совместная работа позволяет минимизировать дублирование исследований, сокращая время, которое проходит от попадания объекта исследований в поле зрения до появления значимых результатов: исправлений в исходном коде, доведенных до репозитория авторов проекта в upstream.
Например, первичный статический анализ ядра Linux 5.10 выявил около сорока тысяч предупреждений. 20 компаний, работая в Консорциуме и объединив усилия, разметили 10 000 из них за год. Сейчас на сайте Консорциума значится около 500 патчей, принятых в основную ветку ядра.
При сохранении количества участников и темпов работ, Консорциум может закончить разметку предупреждений статического анализатора за четыре года. Если компании будут выполнять все исследования самостоятельно, при тех же затратах людских ресурсов такая работа займет десятки лет.
Часть исходного кода в более свежих ядрах не меняется, при их выходе не приходится начинать исследования с нуля, поэтому со временем работа должна ускориться.
Все эти проверки – часть процессов РБПО -разработки безопасного программного обеспечения.
– Что такое РБПО, откуда появилось это понятие?
– Методология РБПО основана на понятии жизненного цикла безопасной разработки ПО, Secure software development lifecycle (SSDLC), ее еще часто называют DevSecOps. SSDLC предусматривает меры по обеспечению безопасности на всех этапах жизненного цикла программного продукта, от разработки требований к ПО до реакции на инциденты во время его эксплуатации.
Разумеется, центральное место в этом процессе занимает разработка и ей уделяется отдельное внимание. Обязательными составляющими РБПО являются статический и динамический анализ. Мы обе эти технологии активно применяем.
– Что такое статический анализ, какие виды анализа еще применяются?
– Есть правила создания безопасного кода, мы их придерживаемся. В наших продуктах используется и собственный код, и свободный код из международных проектов, который необходимо проверить. Проверяется как сам текст программы – это статический анализ, так и корректность ее работы – соответственно, методами динамического анализа.
Расскажу подробнее о статическом анализе кода. Он позволяет выявлять недостатки ПО, не запуская программу. Инструменты анализа проверяют код и помечают подозрительные места. Это своего рода робот-помощник, который экономит время на отсматривание кода глазами. Отмеченные роботом фрагменты кода называют предупреждениями.
Есть универсальные инструменты, которые могут анализировать несколько языков. Есть специализированные для языка C/C++, например, свободные Clang Static Analyzer и CppCheck.
Есть разработанный ИСП РАН анализатор Svace с инструментом разметки Svacer. Он проприетарный, но поддерживает довольно широкий спектр языков: C/C++, C#, Java, Kotlin, Go, Python, Scala, Visual Basic.NET, JavaScript.
В Консорциуме, который создан на базе ИСП РАН, пользуются этим инструментом, так исторически сложилось.
– Инструменты разметки – расскажите подробнее, как с ними работают.
– Инструменты разметки подсвечивают фрагменты кода, помеченные анализатором, позволяют перемещаться по коду программы между найденными предупреждениями и быстро понимать логику, по которой они выставлены. В этой же программе исследователь проставляет комментарии, принимает решение, является ли код ошибочным и подлежит ли он исправлению. Этот процесс называется разметкой. Здесь очень много зависит от квалификации.
– Какими инструментами статического анализа вы пользуетесь?
– По большей части мы используем Svace. Но поскольку ГОСТ требует диверсификации, то есть запрещает пользоваться только одним инструментом, мы применяем и другие. Тот же Clang Static Analyzer, который я уже упоминал.
– Когда анализатор выдал результат, что дальше происходит? Как определяют, что делать с той или иной ошибкой?
– Во-первых, предупреждение может быть истинным, а может быть ложноположительным. В последнем случае мы помечаем его как ошибочное и дальше с ним живем.
Во-вторых, подтвержденное предупреждение тоже может быть разных уровней критичности. От стилистического нарушения, когда просто некрасиво написано, до четкого соответствия одному из видов недостатков.
Недостатки классифицируются по CWE (Common Weakness Enumeration). Это общий перечень проблем и недочетов программного обеспечения, распространенных недостатков кода, принятый в международном сообществе. Не надо путать с CVE (Common Vulnerabilities and Exposures) – списком уже существующих уязвимостей ПО.
Если найденный недостаток соответствует одному из этих CWE, то он, безусловно, требует исправления.
– Какого рода недостатки позволяет выявлять статический анализ? Например, недокументированные возможности программы можно таким образом обнаружить?
– К сожалению, недокументированные возможности, если они заложены логикой программы, выявить статикой невозможно. Если программа написана четко, с соблюдением правил языка, с соблюдением всех норм, но в логику заложена недокументированная возможность, выявить ее может только динамическое исполнение или анализ кода специалистом.
Статический анализатор не может знать, чего хотел программист, и какая из функций программы будет недокументированной, нежелательной или влиять на безопасность.
Анализатор может искать ошибки копирования (copy-paste). Когда программист берет одну конструкцию, копирует, вставляет несколько раз, а потом во вставленном тексте просто меняет, допустим, x на y, y на z и так далее. Инструмент подсвечивает фрагменты, где, допустим, забыли поменять x на y. И другие подобные моменты.
Среди недостатков кода выделяют 25 самых опасных , которые нужно исправлять в первую очередь. Затем исправляются все остальные недостатки, влияющие на работоспособность, и как следствие – на безопасность.
– Если ошибка подтвержденная и подходит под классификацию, что вы делаете дальше?
– Проводится оценка влияния ошибки на безопасность системы. Затем разрабатывается патч для ее исправления, потом полный код программы опять подвергается анализу. Нужно убедиться, что в этом месте предупреждение исчезло.
Напоминаю, большая часть проектов, над которыми мы работаем, это свободное ПО. Его разрабатывают программисты со всего мира, сотни тысяч человек, наверное. Поэтому, когда мы исправляем поведение программы, у нас самый очевидный и приоритетный путь – это пойти в upstream, к оригинальным разработчикам, и предложить им это исправление, чтобы уязвимость была исправлена для всего мира. Это также снимает с нас необходимость поддерживать изменения в собственных сборках программ.
К сожалению, патчи не всегда охотно принимают. Есть те, кто считает «косметические» исправления необязательными. Иногда потенциальные и даже зарегистрированные уязвимости не исправляются длительное время, потому что разработчики, например, считают эти функции сложно эксплуатируемыми или вообще не эксплуатируемыми. Бывает, что ошибка проявляется только в нашей конфигурации, а для всего остального мира она неактуальна.
Тогда мы делаем исправление у себя, его приходится поддерживать, вносить в каждое следующее обновление, а это большой труд. Совместная поддержка таких исправлений также происходит в рамках Консорциума. Вносить исправления в upstream, конечно, предпочтительнее.
Показать актуальность ошибки может помочь разработка так называемого PoC-эксплойта, Proof of Concept, когда разрабатывается кусочек кода или методика для демонстрации этой уязвимости. Запускается программа с неисправленным кодом и выдает нежелательное поведение, которое было предсказано.
Фактически это уже один из видов динамического анализа, которым мы тоже занимаемся.
– Если статическому анализу подвергается исходный код, то динамический – это исследование во время исполнения программы. Какие типы динамического анализа у нас применяются?
– Один из типов динамического анализа – фаззинг.
В 2019 году для сертификации «Альт 8 СП» нам требовалось показать не только результаты статического анализа, но и результаты фаззинга. Эта работа легла на плечи разработчиков. Каждый осваивал технологию по-своему, мы успешно справились и получили первый опыт.
В отличие от традиционных методов тестирования, фаззинг позволяет выявлять сложные ошибки, которые трудно обнаружить методами статического анализа или при функциональном тестировании.
Фаззинг (от английского fuzzy – нечеткий, размытый) – это метод динамического тестирования, при котором в программу подаются случайные, некорректные или специально сгенерированные входные данные с целью выявления сбоев, неожиданных состояний и уязвимостей.
Еще одно значение слова fuzzy – пушистый, что обыгрывается в названии одного из наиболее популярных фаззеров American Fuzzy Lop (AFL), оно происходит от породы кролика.
Фаззеры можно классифицировать по разным критериям, включая метод тестирования, доступность информации о структуре данных и уровень доступа к тестируемой программе.
В нашем арсенале уже больше десятка инструментов с разными областями применения.
Среди них стоит выделить syzkaller – генеративный фаззер, тестирующий взаимодействие с ядром и драйверами путём подачи на вход мутированных системных вызовов.
Для прикладного ПО чаще всего используются AFL++ (и другие разновидности оригинального AFL) и libFuzzer. Это эволюционные или мутационные фаззеры. Они созданы, чтобы экономить время и ресурсы. Такой фаззер не перебирает все возможные случайные варианты, а отслеживает, к чему привело то или иное воздействие. Он отбрасывает бесполезные наборы данных и мутирует полезные, чтобы продвинуться дальше по ходу программы. Очень похоже на эволюцию.
С этим связан еще один термин – «покрытие кода». Известно, что в программе есть определенное количество строк, функций, базовых блоков. Если фаззер выдал набор данных и добрался до очередной строчки или до очередной функции, это означает увеличение покрытия кода. Эти данные учитываются как полезное воздействие и записываются в корпус. Корпус – это набор входных данных, которые приводят к увеличению покрытия.
Если одно из воздействий приводит к падению программы или другому ожидаемому фаззером явлению, в этот момент использованный набор данных представляет собой готовый пример для воспроизведения ошибки.
Очень часто программистам сложно подтвердить или опровергнуть наличие ошибки, когда нет надежного способа ее воспроизведения. А фаззер готовит тот вид данных, которые можно подать на вход программы и воспроизвести ошибку, а это уже половина дела при ее устранении.
– Есть и другие методы динамического анализа помимо фаззинга?
– Еще один метод – функциональное тестирование.
У нас в компании есть отдел тестирования. С выходом новых версий его сотрудники по специально разработанным методикам прогоняют автоматические и ручные тесты с каждой версией программы, выявляя так называемые регрессы. Это появление ошибок, которых раньше не было, или исчезновение функций, которые раньше были.
Следующий метод – юнит-тестирование. Это тесты, которые в самом коде программы обычно предусматривает программист.
При сборке пакета, если исходный код содержит юнит-тесты, сопровождающие пакета (мейнтейнеры) всегда стараются их запускать. Это кусочки кода, которые передают функциям программы заранее известный ввод и ожидают заранее известный отклик. Если вдруг что-то отличается, то тесты падают. И на этом основании пакет не собирается до того, как придет мейнтейнер пакета или программист и устранит ошибку. Это может быть ошибка в коде, неправильная версия библиотеки или ошибка сборки на конкретной платформе. Допустим, на архитектуре x86_64 пакет собирается, а на aarch64 перестает собираться или не проходит тест.
Мы используем в динамическом анализе практически для всех программ, как минимум, три техники: фаззинг, функциональное тестирование и юнит-тестирование.
– Какие еще методы, кроме статического анализа и фаззинга, вы применяете?
– Мы активно используем определение поверхности атаки и композиционный анализ.
Поверхность атаки – это совокупность всех точек взаимодействия системы с внешней средой, через которые потенциальный злоумышленник может попытаться осуществить атаку. Это могут быть сетевые интерфейсы, API, файловая система, библиотеки и даже пользователи с различными уровнями доступа. Минимизация поверхности атаки – одна из ключевых задач обеспечения безопасности.
Все внутренние разработки и компоненты свободного ПО, определенные как элементы поверхности атаки наших продуктов, обязательно проверяются различными доступными методами.
Композиционный анализ сложного ПО (или построение software bill of materials, сокращенно SBoM) позволяет определить полный перечень используемых компонентов, включая заимствованные библиотеки и их зависимости. Это помогает выявлять уязвимые или устаревшие модули, обеспечивая прозрачность цепочки поставок программного обеспечения. Такой анализ критически важен для управления безопасностью и соблюдения нормативных требований.
– Создается впечатление, что практики РБПО – это огромная работа, как вы с ней справляетесь? Есть какая-то автоматизация?
– С самых первых дней было понятно, что мы тратим очень много времени на ручной запуск исследований, отслеживание их результатов. Требовалась система, которая бы автоматически запускала уже разработанные методики, приглядывала за ними, собирала с них метрики, регистрировала падения, сохраняла результаты в базе данных – чтобы получать только пищу для размышлений с минимумом рутины.
И мы создали инструмент Hantis, конвейер автоматизации, который позволяет всё это делать. Название происходит от одноименного вида спорта (Hantis – от Hand Tennis). В него играют от двух до четырех человек на четырех столах. Процесс исследований очень похож именно на этот вид спорта. Проекты, исследуемые разными инструментами, переходят от одного исполнителя к другому, развиваются, возвращаются к автору, и так по кругу.
Мы обобщили опыт методик фаззинга из разных проектов и разработали структуру инструментального Git-репозитория таким образом, чтобы можно было пакеты из Sisyphus и его стабильных бранчей как бы обволакивать этим инструментальным репозиторием, подключаться к ним сбоку. И при обновлении версии ПО в Sisyphus или его бранче просто воспроизводить очередные исследования.
Фаззинг может длиться днями и месяцами. Поскольку большая часть исследований ведется в контейнерах, мы решили в основу Hantis заложить Kubernetes.
Не все процессы анализа можно поместить в контейнеры, некоторые из них требуют использования виртуальных машин, с которыми Kubernetes не может работать напрямую. Также есть типы анализа, которые выполняются быстро, в отличие от фаззинга.
Чтобы эти разнородные процессы включить в один общий конвейер, мы создали механизм расширения, назвали эти плагины Hunters – «охотники».
Всё это мы разрабатываем под свободной лицензией GNU AGPLv3, и планируем обнародовать, когда код будет готов к релизу.
– С такой автоматизацией вы сможете быстрее завершить все проверки и полностью подтвердить безопасность ПО?
– ГОСТ Р 56939-2024 «Защита информации. Разработка безопасного программного обеспечения. Общие требования» предусматривает 25 обязательных мероприятий, начиная с обучения работников и планирования требований к самому ПО, далее проходя все стадии: написание кода, исследование кода, проверка перед внедрением, функциональное тестирование, реакцию на инциденты безопасности при его эксплуатации и так далее. И вновь возвращается на этап планирования. Это замкнутый круг, который никогда не заканчивается.
Ключевые слова: безопасное ПО, автоматизация, динамический анализ, статический анализ, фаззинг, функциональное тестирование, юнит-тестирование
Подпишитесь на журнал
Facebook
Мой мир
Вконтакте
Одноклассники
Google+
|