Представляю вашему вниманию продолжение перевода второй главы Owasp Testing Guide. В данной статье речь пойдет о тестировании безопасности во время разработки.

Тестирование безопасности на стадиях разработки и тестирования

Тестирование безопасности на стадии разработки

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

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

Тестирование безопасности на стадии тестирования

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

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

Целью тестов безопасности является полноценная система, которая потенциально будет атакована, и она включает в себя как исходный код приложения, так и исполняемый его элемент. Особенностью тестирования безопасности на данном этапе является возможность определить то, могут ли уязвимости быть эксплуатированы и подвергнуть приложение реальным рискам. Это включает в себя общеизвестные уязвимости веб-приложений, а также проблемные места в безопасности, которые были обнаружены ранее в ЖЦ.

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

Тест-инженеры, проверяющие безопасность приложения, могут развернуть его на боевой среде для тестирования (например, тест приёмки пользователями). На данной стадии ЖЦ функциональное тестирование приложения является зоной ответственности команды контроля качества, в то время как белые хакеры или консультанты по безопасности обычно ответственны за тестирование безопасности. Некоторые организации используют собственную команду этичных хакеров для проведения таких тестов, когда в тестировании сторонней организацией нет необходимости (например, для аудита).

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

Тестирование безопасности для разработчиков

Тестирование безопасности в процессе написания кода: модульное тестирование

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

Требования безопасности, которым разработчики должны следовать, должны быть задокументированы в стандартах безопасного программирования и подтверждены с помощью статического и динамического анализа. Если юнит-тесты производятся после проверки безопасности кода, они могут подтвердить, что изменения в коде, требуемые по итогам проверок, внедрены должным образом. Проверки безопасного кода и анализ исходного кода специальными инструментами помогают разработчикам с поиском проблем безопасности в процессе написания кода. Используя юнит тесты и динамический анализ (например, отладку) разработчики могут подтвердить безопасность функционирования компонентов, а также проверить то, что разрабатываемые контрмеры смягчают найденные ранее риски безопасности.

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

  • Идентификация, аутентификация и контроль доступа,
  • Проверка и кодирование ввода,
  • Шифрование,
  • Управление пользователями и сессиями,
  • Обработка ошибок и исключений,
  • Аудит и логирование.

Разработчики, вооруженные инструментами анализа исходного кода, включенного в их IDE, стандартом безопасного программирования и фреймворком для юнит-тестов могут проверить и подтвердить безопасность разрабатываемых компонентов ПО. Тесты безопасности могут быть запущены для определения потенциальных проблем, которые имеют корневую причину в исходном коде: несмотря на подтверждение входных и выходных данных у параметров входа и выхода из компонентов, эти проблемы включают проверки аутентификации и авторизации самим компонентом, защищённость данных внутри компонента, безопасные исключения и обработку ошибок, а также безопасный контроль системы и логирование. Фреймворки для юнит-тестов, такие как Junit, Nunit и CUnit могут быть адаптированы для подтверждения требований тестов безопасности. В случае с функциональными тестами безопасности, тесты модульного уровня могут проверить функциональность механизмов безопасности на уровне компонентов приложения, таких как функции, методы и классы. Например, тест может подтвердить проверку ввода и вывода или проверку границ для значений переменных, утверждая тем самым ожидаемую функциональность компонента.

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

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

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

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

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

Функциональные тесты безопасности

Тестирование безопасности на стадиях интеграции и утверждения: интеграционные и эксплуатационные тесты

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

Среда интеграционного тестирования является первой средой, где тестировщики могут имитировать реальные сценарии атак, которые могут потенциально быть исполнены внешним или внутренним злоумышленником. Тестирование безопасности на данном уровне может подтвердить наличие уязвимостей и возможность их эксплуатации атакующими. Например, уязвимость, найденная в исходном коде, может быть оценена как высокорисковая из-за возможности исполнения злоумышленниками и потенциального воздействия (например, доступ к конфиденциальной информации).

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

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

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

Более углублённые тесты безопасности могут требовать знания тестировщика о специализированных техниках и инструментах тестирования. Кроме анализа исходного кода и пентеста, эти техники включают, например, инъекции в исходный код, анализ воздействия неисправности и обработки её кодом, «случайное» тестирование (прим. fuzz testing) и реверс-инжиниринг. Руководство по тестированию безопасности должно предоставлять процедуры и рекомендуемые инструменты, которые могут быть использованы тестировщиками безопасности для проведения таких доскональных проверок ИБ.

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

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