Безопасная разработка ПО
Популярность цифровизации привела к тому, что программное обеспечение сейчас становится основой экономики и практически любой человеческой деятельности. Однако в нем по-прежнему остаются ошибки, которые могут привести к неожиданным последствиям для пользователей ПО. Разбираемся, можно ли избавиться от наиболее опасных ошибок в программном коде, и что нужно для этого сделать.
Есть очень много классов ошибок, из которых наиболее опасным является удаленное исполнение программного кода без взаимодействия с пользователем. Такой метод часто используют хакеры для скрытого проникновения в информационные системы или авторы червей и вирусов для написания своих саморазмножающихся кодов. Для оценки опасности ошибок американская организация MITRE предложила классификацию Common Vulnerability Scoring System (CVSS) – сейчас действует уже третья версия ее спецификации. В ней уязвимость оценивается по шкале от 0 до 10 по нескольким критериям: простота и вероятность эксплуатации, а также ущерб, который можно нанести с помощью эксплуатации этой уязвимости, и множество других метрик.
Три метода анализа
Для обеспечения безопасности программных кодов существует три семейства технологий анализа на безопасность: статический и динамический анализ, а также фаззинг.
Статический
Статический анализ проводится непосредственно с исходными кодами. Собственно, частично анализаторы кода встроены в сам компилятор – он выдает предупреждения для наиболее часто встречающихся ошибок. Однако специализированные анализаторы проверяют не только структуру исполнения программы, но и анализируют достижимость каждой описанной ветки кода, строят диаграммы передачи данных в процессе исполнения программы и выполняют ещё достаточно много проверок, с помощью которых можно выявить потенциально опасные места.
Статический анализатор считает некоторую часть программных конструкций некорректными – опасными с точки зрения безопасности. Именно на этом основана технология безопасной разработки – исключение из практики тех конструкций языка программирования, которые могут привести к уязвимостям. Как правило, разработчики статических анализаторов перечисляют набор конструкций, которые считаются опасными с обоснованием такой классификации. Однако часто программисты пользуются этими конструкциями для оптимизации размера кода или производительности, причем эти приемы могут быть безопасными. Поэтому прежде, чем какую-то часть кода считать опасной, нужно очень подробно ее проанализировать и определить действительно ли она представляет угрозу или, как и в большинстве случаев, это безопасное использование необычной для компилятора конструкции. В целом можно отметить, что статистический метод анализа дает большое количество ложно-положительных срабатываний, и поэтому требует тщательной ручной проверки результатов своей работы.
Динамический
Анализ поведения программы выполняется также с использованием исходных кодов, но только во время компиляции в исполнимый код вставляются специальные ловушки, которые в нужное время перехватывают исполнение программы и проверяют состояние ее окружения. Дебаггером, который и представляет собой самый простой вариант динамического теста, часто пользуются и сами программисты в процессе разработки, чтобы понять, как их программа работает. Именно динамический анализ позволяет выявить сложные проблемы в конфигурации приложений и провести пошаговый анализ происходящих в нем событий. Этот набор проверок позволяет также выявить не используемые фрагменты кодов – если пометить каждый фрагмент во время запуска и после проведения всех функциональных тестов во всех возможных режимах найти не помеченные фрагменты кода, то логично предположить, что они либо избыточны, либо представляет собой те самые "недекларированные возможности". Конечно, они могут быть и безобидным "пасхальным яйцом", однако могут представлять, в том числе, и вредоносную закладку. Именно так и проводилась сертификация во ФСТЭК на отсутствие НДВ. Однако даже динамический анализ не дает гарантии обнаружения всех ошибок, поскольку он проверяет работу программы в штатном режиме и не анализирует обработку программой различных вариантов пользовательских данных. В то же время именно обработка таких данных – сетевых пакетов, введенных веб-запросов или полей базы данных – как раз и используется для эксплуатации большинства наиболее опасных уязвимостей.
Стресс-тестирование (фаззинг)
Это метод, при котором на все входы программы в случайном порядке подаются самые разнообразные данные с целью вывести ее из строя. Он может проводиться без наличия исходного кода в так называемом режиме «черного ящика». Когда происходит сбой в программе, анализируется слепок памяти программы прямо перед выполнением запрещенной операции и выясняется, как программа попала в такую сложную ситуацию. По состоянию памяти после сбоя восстанавливается вся последовательность вызовов и обнаруживается ситуация, которая вызвала ошибку. Выход программы из строя и позволяет обнаружить в ней уязвимость, именно поэтому методы стресс-тестирования программ обычно являются частью цикла безопасной разработки ПО – вместе со статическим и динамическим тестами они обычно входят в циклы тестирования ПО после разработки.
Однако фаззинг – это случайный процесс, поэтому нет ни какой гарантии, что и в процессе такого тестирования будут полностью изучены все возможные варианты неправильного ввода данных в программу. Да, процедуры фаззинга стараются делать достаточно много раз, чтобы гарантировать максимально возможное покрытие тестами. Важно при составлении тестовых данных для ввода в программу перебрать максимально много различных вариантов составления некорректных последовательностей.
Зачем тестировать программы?
Процедуры безопасной разработки программного обеспечения или, как сейчас модно назвать, DevSecOps как раз и предполагают проведение всех возможных тестов программы, включая фаззинг, перед ее запуском в продажу. Естественно, все обнаруженные проблемы разработчики должны самостоятельно обработать и устранить перед передачей потребителю. Кроме того, должна быть предусмотрена процедура обновления программного обеспечения для устранения уязвимостей, если такие будут обнаружены в процессе эксплуатации, – ведь в некоторых случаях уязвимости возникают при работе в каком-то определенном окружении. Все это предусмотрено стандартом ГОСТ Р 56939-2016 «Защита информации. Разработка безопасного программного обеспечения. Общие требования», который разработан ФСТЭК ещё в 2016 году и сейчас является основой процедуры сертификации ПО по уровням доверия. Наиболее доверенным считается ПО, которое прошло все необходимые проверки и не имеет изъянов в реализации. Причем частично работа по сертификации может быть проведена самим разработчиком при реализации требований указанного выше стандарта и внедрении у себя цикла безопасной разработки DevSecOps. Результаты финального тестирования могут быть зачтены регулятором в процессе сертификации.
Для потребителей программного обеспечения важно проверять имеет ли программа, которую он покупает, сертификат по уровню доверия или нет – это требование должно быть прописано в ТЗ на приобретение того или иного ПО. Только так можно быть уверенным, что программное обеспечение, прежде чем попало потребителю, прошло все необходимые проверки на безопасность кода. Причем, поскольку стандарт предполагает наличие системы устранения уязвимостей уже после ее развертывания, то реализация у производителя стандарта безопасной разработки ещё более предпочтительна, поскольку гарантирует техническое сопровождение в дальнейшем и исправление уязвимостей, которые были найдены в процессе эксплуатации. ФСТЭК следит за уязвимостями в сертифицированном ПО и публикует сведения о них в своей базе данных угроз и уязвимостей. Появление в соответствующей базе данных сведений является требованием для разработчика по устранению обнаруженной уязвимости. Если производитель не устранил обнаруженную уязвимость, то сертификат на соответствующее ПО может быть отозван. Так что современный сертификат ФСТЭК по уровням доверия – это не простая формальная проверка, которая устаревает ещё до ее получения производителем, но определенная гарантия, что производитель имеет все необходимые инструменты не только для устранения уже обнаруженных проблем, но и для решения их в будущем, если они будут обнаружены.
Подготовил Валерий Коржов