Безопасная разработка для Staffcop (системы расследования инцидентов внутренней инфобезопасности) — это не отдельная проверка перед релизом, а процесс, который команда постепенно встраивает в работу с кодом. С одной стороны, это связано с требованиями регулятора и подготовкой продукта к сертификации. С другой — помогает находить уязвимости раньше, до того, как код попадёт в общую ветку, пройдёт все стадии разработки и дойдёт до пользователя.

В команде уже тестируют инструменты для разных видов анализа: статического, композиционного, динамического, фаззинга и поиска секретов. Один из первых подробно разобранных этапов — пилот статического анализатора кода.

Какие есть требования и зачем их соблюдать

У Staffcop есть требования от регулятора, в том числе от ФСТЭК. Продукт проходит подготовку к сертификации, а сертификация проводится по определённым правилам и уровням доверия. Для этого заявитель должен предоставить результаты проверок. В этот набор входит и статический анализ кода.

Для компании сертификация нужна не только как формальность. Сертификат открывает доступ к рынкам, где наличие подтверждённого соответствия — одно из ключевых условий для работы с продуктом.

Но безопасная разработка важна не только ради сертификации. Её задача — снизить количество уязвимостей в продукте. В идеальной модели команда находит проблемные конструкции на раннем этапе: когда разработчик только пытается влить код в общий репозиторий.

Если проверка встроена в процесс, хорошо настроенный анализатор видит конструкции, которые не соответствуют требованиям, стилю или логике уже написанного кода. Такой код не попадает дальше по цепочке. Команда исправляет проблему не после релиза, а на этапе «Непрерывной интеграции» (пайплайн CI/CD). 

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

Как мы внедряем безопасную разработку

Команда по очереди пилотирует доступные инструменты анализа. Для каждого направления проверяют несколько решений на одной и той же версии исходного кода и на синтетических тестах. Такой подход помогает сравнить инструменты в одинаковых условиях и наиболее подходящие внедрить в процесс разработки.

Сейчас в фокусе несколько направлений.

  • Статический анализ. Инструмент проверяет код до запуска продукта. Он ищет уязвимые конструкции в исходном коде, а также, если поддерживает такую возможность, в результатах компиляции и связанных артефактах. После проверки разработчики проводят триаж: смотрят результаты, отделяют значимые срабатывания от ложноположительных и исправляют найденные проблемы.

  • Композиционный анализ. Этот этап нужен, чтобы проверить состав продукта: какие внешние зависимости и сторонние библиотеки используются при сборке. Речь идет в том числе об open source компонентах, которые написали сторонние разработчики. Их тоже нужно контролировать, потому что в таких зависимостях могут быть уязвимости.

  • Динамический анализ. Здесь проверяется уже собранный продукт. Инструменты работают с поверхностью атаки: интерфейсами и точками входа, через которые можно передать данные, команду или эксплойт, и проверить, как продукт реагирует.

  • Фаззинг. Это близкий к динамическому анализу подход, но вместо корректных данных инструмент подаёт некорректные или неожиданные данные. Например, строку из большого количества символов. Если интерфейс ведёт себя неправильно, пропускает пользователя дальше или ломается непредсказуемым образом, это признак уязвимости.

  • Поиск секретов. Команда отдельно проверяет, не попали ли в исходный код пароли, ключи, доступы и другие секреты. Таких данных в коде быть не должно.

  • Тестирование. В общую логику безопасной разработки входят модульные, регрессионные и нагрузочные тесты.

  • Единый центр управления безопасной разработкой. В планах — пилотирование системы, которая собирает данные из разных анализаторов и показывает статус по проектам в одном окне. В идеале это такой центр управления безопасной разработкой, ASOC.

При выборе инструментов мы опираемся на список составленных нашей командой разработки требований. Он состоит из ряда общих требований, применимых для всех анализаторов, и специальных требований для каждого отдельного вида анализа. Таким образом, к каждому из рассматриваемых инструментов применимы порядка 30 критериев для отбора.

Внедрение усложняется тем, что у продукта Staffcop мультиязычная архитектура. Разные модули написаны на разных языках: С/C++, Rust и Python. Поэтому проверки нужно пройти на разных частях продукта, а не только на одном типе кода.

В пилотировании участвует команда из восьми человек. Задачи распределяются в зависимости от этапа и инструмента. Состав команды меняется: часть разработчиков возвращается к основной работе с кодом, другие подключаются к задачам безопасной разработки. Так команда поддерживает общий контекст и развивает культуру безопасной разработки внутри продукта.

Изначально пилотирование планировали завершить за шесть месяцев. Срок сдвинулся примерно на месяц из-за подготовки поверхности атаки для динамического анализа и фаззинга. Эту работу нужно было провести заранее, потому что без описанных точек входа нельзя полноценно проверить инструменты динамического анализа.

Что уже сделано: анализатор кода

Один из первых подробно проработанных этапов — статический анализатор кода. Мы начали проверку с PVS-Studio и параллельно тестируем другие инструменты. 

Статический анализатор нужен, чтобы автоматизировано найти уязвимые конструкции до запуска продукта. Он проходит по коду, формирует отчёт и показывает разработчику места, которые требуют проверки. После этого разработчик проводит триаж и решает, какие срабатывания нужно исправить.

Технически пилот выглядит так: 

  • Сначала запросили у вендора пилот и тестовый ключ. 

  • Затем изучили документацию, подготовили сервер под требования продукта, развернули анализатор и передали ему код для проверки.

  • PVS-Studio анализировал файл проекта и выдавал отчёт. После этого специалисты вручную просматривали результаты. Такой этап нельзя полностью убрать: ложноположительные срабатывания неизбежны, и человек лучше удерживает контекст, чем алгоритм.

Кроме реального кода использовали синтетические тесты. Это небольшие фрагменты кода, в которых заранее известно, есть уязвимость или нет. В выборке тестов, которую мы используем, ошибки разделены на классы по системе CWE. И они помогают понять, какие типы ошибок может находить анализатор, а какие — нет. 

Синтетические тесты нужны до проверки на реальном коде. Они помогают отсеять инструменты, которые из коробки показывают слишком слабый результат: почти ничего не находят, находят не то, что ожидается, или требуют слишком большой донастройки. Если инструмент на базовом наборе тестов не показывает адекватный результат, нет смысла сразу запускать его на кодовой базе продукта.

Что показало тестирование PVS Studio

Инструмент удобен в работе за счёт простоты использования, наличия плагинов для IDE и большому количеству интеграций, и имеет сравнительно высокую скорость выполнения анализа.

При этом зафиксировано, что инструмент демонстрирует ограниченную глубину анализа применительно к ошибкам, требующим прослеживания сложных межпроцедурных связей или нетривиальной логики выполнения. В ряде случаев анализатор оказывается чувствителен к определённым синтаксическим или потоковым конструкциям, которые могут провоцировать ложные срабатывания, не соответствующие реальным уязвимостям. В сравнении с другими протестированными решениями PVS Studio регистрировал дефекты меньшей алгоритмической сложности и реже обнаруживал нетривиальные, «хитрые» ошибки. 

Вместе с тем PVS Studio показал способность выявлять уязвимости в исходном коде, которые могут быть скрыты после работы компилятора (например, CWE-762). Эта особенность выгодно отличает его от ряда других анализаторов, нечувствительных к подобным конструкциям.

Выводы о глубине анализа сделали на основании субъективного мнения разработчика, проводившего триаж PVS Studio и ряда других анализаторов.

Для наглядности можно привести пример типовой конструкции для языка C++, вызывающей ложно-положительные срабатывания анализатора. Наиболее предпочтительным способом управления памятью в C++ считается концепция RAII (Resource Acquisition Is Initialization), позволяющая значительно упростить контроль за выделением и освобождением ресурсов даже в случае возникновения исключений. Её выполнение поддерживается рядом стандартных конструкций языка. Однако во многих системных библиотеках, в особенности написанных на языке си, эта концепция не поддерживается или невозможна. Для таких случаев, а также для выполнения менее тривиальных задач при выходе из области видимости, мы используем классический приём в виде специального класса-обёртки, вызывающего переданную ему функцию в деструкторе. Но его использование практически всегда вызывает ложно-положительные срабатывания у PVS Studio, который не может проследить связь между вызовом деструктора у обьекта-обёртки и освобождением связанных с ним данных.

Важно отметить, что пилотирование полезно обеим сторонам: стороне, внедряющей анализатор в свой процесс разработки, и самим разработчикам анализатора. Команда разработки PVS Studio серьёзно отнеслась к результатам нашего пилотирования и ко всем найденным типовым источникам ложно-положительных срабатываний. Стоит ожидать, что в скором времени инструмент станет обрабатывать их лучше.

Что дальше

Дальше команда продолжит пилотирование по остальным направлениям безопасной разработки. И мы выпустим ещё несколько обзоров подобных инструментов 

Ближайшие этапы — завершение статического и композиционного анализа. По словам участников интервью, работа по этим направлениям уже близка к завершению. Дальше команда планирует рассказывать минимум о нескольких статических и композиционных анализаторах.

После этого фокус сместится на динамический анализ и фаззинг. Для этих этапов особенно важна подготовленная поверхность атаки: список интерфейсов и точек, через которые можно проверять поведение продукта при корректных и некорректных входных данных.

Также в планах остаётся поиск секретов в исходном коде, развитие тестирования и пилотирование единой системы, которая будет собирать данные из разных анализаторов в одном окне.

Итоговая цель — не просто выбрать один инструмент. Команда собирает практический контур безопасной разработки: требования, проверки, инструменты, процессы триажа и понятную картину по состоянию проектов. Такой подход помогает одновременно  готовиться к сертификации, снижать риски в продукте и развивать культуру безопасной разработки внутри команды.