Дифференциальное тестирование [1] , также известное как дифференциальный фаззинг , представляет собой метод тестирования программного обеспечения , который обнаруживает ошибки , предоставляя одинаковые входные данные для ряда похожих приложений (или для различных реализаций одного и того же приложения) и наблюдая различия в их выполнении. Дифференциальное тестирование дополняет традиционное тестирование программного обеспечения, поскольку оно хорошо подходит для поиска семантических или логических ошибок , которые не демонстрируют явного ошибочного поведения, такого как сбои или сбои утверждений. Дифференциальное тестирование также называется тестированием back-to-back.
Дифференциальное тестирование обнаруживает семантические ошибки, используя различные реализации одной и той же функциональности в качестве перекрестных ссылок на оракулы , выявляя различия в их выходных данных при одних и тех же входных данных: любое несоответствие между поведением программы при одних и тех же входных данных помечается как потенциальная ошибка.
Дифференциальное тестирование использовалось для успешного поиска семантических ошибок в различных областях, таких как реализации SSL/TLS , [2] [3] [4] [5] компиляторы C , [6] реализации JVM , [7] брандмауэры веб-приложений , [8] политики безопасности для API , [9] антивирусное программное обеспечение , [4] [10] и файловые системы . [11] Дифференциальное тестирование также использовалось для автоматизированной генерации отпечатков пальцев из различных реализаций сетевых протоколов . [12]
Неуправляемые дифференциальные инструменты тестирования генерируют тестовые входные данные независимо друг от друга на всех итерациях, не принимая во внимание поведение тестовой программы на прошлых входных данных. Такой процесс генерации входных данных не использует никакой информации из прошлых входных данных и по сути создает новые входные данные случайным образом из непозволительно большого входного пространства. Это может сделать процесс тестирования крайне неэффективным, поскольку для обнаружения одной ошибки необходимо сгенерировать большое количество входных данных.
Примером системы дифференциального тестирования, которая выполняет неуправляемую генерацию входных данных, является «Frankencerts». [2] Эта работа синтезирует Frankencerts путем случайного объединения частей реальных сертификатов. Она использует синтаксически действительные сертификаты для проверки семантических нарушений проверки сертификатов SSL/TLS в нескольких реализациях. Однако, поскольку создание и выбор Frankencerts полностью неуправляемы, она значительно неэффективна по сравнению с управляемыми инструментами.
Процесс направленной генерации входных данных направлен на минимизацию количества входных данных, необходимых для поиска каждой ошибки, путем учета информации о поведении программы для предыдущих входных данных.
Примером системы дифференциального тестирования, которая выполняет генерацию входных данных, ориентированную на покрытие конкретной области, является Mucerts. [3] Mucerts опирается на знание частичной грамматики формата сертификата X.509 и использует алгоритм стохастической выборки для управления генерацией входных данных, отслеживая при этом покрытие программы.
Другое направление исследований основано на наблюдении, что проблема генерации новых входных данных из существующих входных данных может быть смоделирована как стохастический процесс. Примером инструмента дифференциального тестирования, который использует такое моделирование стохастического процесса для генерации входных данных, является инструмент Чена и др. [7]. Он выполняет дифференциальное тестирование виртуальных машин Java (JVM) с использованием выборки Монте-Карло с цепями Маркова (MCMC) для генерации входных данных. Он использует пользовательские мутации, специфичные для домена, используя подробные знания о формате файла класса Java.
NEZHA [4] является примером инструмента дифференциального тестирования, который имеет механизм выбора пути, ориентированный на доменно-независимое дифференциальное тестирование. Он использует определенные метрики (называемые дельта-разнообразием), которые суммируют и количественно определяют наблюдаемые асимметрии между поведением нескольких тестовых приложений. Такие метрики, которые способствуют относительному разнообразию наблюдаемого поведения программы, показали свою эффективность в применении дифференциального тестирования доменно-независимым и черным ящиком способом.
Для таких приложений, как фильтры межсайтового скриптинга (XSS) и проверка имени хоста сертификата X.509, которые можно точно смоделировать с помощью конечных автоматов (FSA), можно использовать методы обучения FSA на основе контрпримеров для генерации входных данных, которые с большей вероятностью найдут ошибки. [8] [5]
Символическое выполнение [13] — это метод «белого ящика» , который выполняет программу символически, вычисляет ограничения по разным путям и использует решатель ограничений для генерации входных данных, которые удовлетворяют собранным ограничениям по каждому пути. Символическое выполнение также может использоваться для генерации входных данных для дифференциального тестирования. [12] [14]
Внутреннее ограничение инструментов тестирования с использованием символического выполнения — взрывной рост путей и масштабируемость — особенно усиливается в контексте дифференциального тестирования, где используются несколько тестовых программ. Поэтому очень сложно масштабировать методы символического выполнения для выполнения дифференциального тестирования нескольких больших программ.