Модульное тестирование – это уровень тестирования программного обеспечения, при котором тестируются его отдельные модули или компоненты. Цель – подтвердить, что работа каждой единицы программного обеспечения соответствует ожиданиям. Модулем называется наименьшая тестируемая часть любого ПО. Обычно он имеет один или несколько входов и, как правило, только один выход.
Модульные тесты часто пишутся в IDE и хранятся вместе с кодом в репозитории. Они почти так же ценны, как и сам код. В идеале перед загрузкой кода разработчики выполняют все модульные тесты, и, если код не проходит тест, разработчик должен либо 1) исправить код, либо 2) адаптировать тест к новым изменениям кода. Не разрешается загружать сломанный код, который не прошел модульные тесты.
СОВЕТ. Часто при обсуждении модульных тестов люди говорят о «покрытии кода». Покрытие кода показывает процент кода, проверенного с помощью модульного тестирования. Стандартного значения не существует, и тем не менее каждая организация стремится к 100 % покрытия. В реальности же редко можно встретить очень высокое покрытие кода. Постарайтесь не быть слишком строгими к своим разработчикам, если они находятся далеко от идеальных 100 %: мало кто приближается к этому показателю.
Модульные тесты, как правило, являются позитивными, то есть они проверяют, чтобы код всегда выполнял заложенные в него функции. Тем не менее они могут быть и негативными. Их цель – проверить, что приложение правильно отказывает в совершении операции, если получает ненадлежащие входные данные. Негативные модульные тесты часто используются для проверки не только качества приложения, но и его безопасности.
Для проведения негативных модульных тестов поговорите с разработчиками и получите разрешение на «копание» в их коде. Затем скопируйте несколько их модульных тестов, приставьте к ним в конец элемент, обозначающий негативную версию теста (например, _abuse
), и добавьте соответствующую полезную нагрузку (потенциально проблемный код). Запустите негативные модульные тесты и выясните, какой код проходит их успешно, а какой – нет.
СОВЕТ. Если у вас на работе реализуется программа чемпионов по безопасности, попросите одного из них о помощи. Это прекрасная возможность улучшить навыки чемпиона в сфере безопасности, и со временем можно будет передать эту задачу ему. Если нет, не волнуйтесь. Мы поговорим об инициировании программы чемпионов по безопасности в последующих главах.
Например, если код будет выведен на экран, попытайтесь добавить в него тег <script>
, затем убедитесь, что код правильно зашифровывает и не выполняет его. Это довольно экстремальный пример: если код выполнит тег, значит, у вас большие проблемы. Команда OWASP создала удобную «Шпаргалку по уклонению от XSS-фильтра», которая, без сомнений, является отличным помощником для начала работы с полезной нагрузкой (плохим кодом, добавляемым в негативные модульные тесты). Можно добавить логические тесты, ненадлежащие входные данные, повторное тестирование проблем, обнаруженных в ходе ручного тестирования безопасности, и тесты для всех разработанных моделей угроз.
Основная ценность модульных тестов, как негативных, так и позитивных, заключается в регрессионном тестировании. Регрессионное тестирование – это повторное выполнение функциональных и нефункциональных тестов с целью подтверждения того, что ранее разработанное и протестированное программное обеспечение продолжает работать после внесения изменений. Негативные модульные тесты обеспечивают автоматизированное регрессионное тестирование безопасности, которое чрезвычайно полезно на ранних этапах жизненного цикла разработки ПО. Они требуют предварительной подготовки и обслуживания, но результат их выполнения весьма действенен с точки зрения безопасности.
СОВЕТ. Если в компании проводятся тесты на проникновение, оценка обеспечения безопасности или оценка уязвимости, подумайте о создании модульных тестов на основе результатов этих проверок (в надлежащих случаях). Таким образом вы сможете убедиться, что допущенные ранее ошибки не повторятся. Более того, если у вас есть разрешение, примените полученные из итогового отчета знания ко всем приложениям, с которыми работаете. Создайте модульные тесты для всех возможных приложений. Разработчики обычно работают над несколькими проектами, и они могли допустить одну и ту же ошибку в нескольких местах.
Давным-давно, когда Боб еще занимался технической работой, а не управлял проектами, как сейчас, серверы назывались милыми именами в честь героев телешоу. Каждый сервер был отдельной физической машиной, и Боб помнит, как приходилось устанавливать их в стойки, какими тяжелыми и шумными они были. Он не забыл, как ему нужно было ходить от машины к машине с установочным компакт-диском, чтобы обновить операционную систему. Со временем появилась возможность получать обновления через интернет, и это заметно облегчило жизнь, но Боб все равно должен был ходить и нажимать кнопку Next столько раз, что уже и не упомнить.
Со временем компания перешла на виртуальные машины (ВМ). Теперь несколько операционных систем могли находиться на одном сервере. К тому моменту уже все было подключено к сети, и обновления скачивались из интернета, а не с компакт-дисков. Стали использоваться автоматизированные системы для установки патчей, и больше не было необходимости по вечерам нажимать кнопку Next или ходить от машины к машине. Боб был в восторге от такого прогресса. Сейчас у них есть DevOps-специалисты и инженеры по надежности сайтов (SRE), которые занимаются чем-то под названием «инфраструктура как код», но их работа гораздо выше уровня понимания Боба, поэтому он занимается управлением проектами, а заботу о технических деталях оставил им.
Инфраструктура как код (англ. Infrastructure as Code, IaC) – это подход для управления и описания инфраструктуры центра обработки данных через конфигурационные файлы, а не через ручное редактирование конфигураций на серверах или интерактивное взаимодействие.
Википедия
Инфраструктура как код (IaC), иногда называемая конфигурацией как код, определяет инфраструктуру с помощью написанного кода, в отличие от образа системы или установочного файла. Этот код может быть запущен для создания, замены или обновления инфраструктуры. Как и код приложения, он хранится в репозитории кода или выпускается через конвейер CI/CD.
Результаты IaC более однородны, а если код хранится в репозитории кода, то любые изменения можно легко отследить, проверить и при необходимости откатить назад. Как и к любому другому коду, к IaC можно применять тестирование безопасности.
ПРИМЕЧАНИЕ. IaC проверяет все виды компоненты безопасности: управление изменениями, аварийное восстановление, устранение возможности опечаток и многое другое. Хотя темой книги является создание безопасного программного обеспечения, код живет на серверах, и поэтому он имеет важное значение. Кроме того, код есть код. Давайте защитим его в полном объеме.
Безопасность как код (англ. Security as code, SaC) – это практика встраивания элементов безопасности в инструменты и рабочие процессы DevOps путем составления схемы внесения изменений в код и инфраструктуру, а также поиска мест, куда можно добавить проверки, тесты и ограничения без лишних затрат и задержек.
О’Райли
Если разработчики автоматизируют все, даже инфраструктуру, мы должны автоматизировать и обеспечение безопасности. Существует множество различных способов реализации концепции SaC, но в этом разделе мы сосредоточимся на том, как проверить IaC на наличие проблем, связанных с обеспечением безопасности. Идею автоматизации проверок безопасности мы рассмотрим в следующих главах, когда будем обсуждать DevOps и DevSecOps.
Код, написанный для IaC, можно проверить на наличие проблем, как и любой другой код, однако его необходимо протестировать до выпуска в эксплуатацию (не позже). IaC, в частности, следует не только проверить на уязвимости, но и убедиться в том, что тот, кто писал определения инфраструктуры, включил необходимые функции безопасности и конфигурации для каждого определения инфраструктуры: принудительное использование HTTPS для виртуальной машины веб-сервера, использование версии TLS, закрытие портов, размещение контейнера внутри определенной V–LAN в локальной сети и т. д.
СОВЕТ. Обеспечьте защиту безопасности как кода и инфраструктуры как кода так же, как и защиту кода приложения: храните их в версионном репозитории кода, отслеживайте изменения, следите за тем, кто имеет доступ, и регулярно создавайте резервные копии.