Среди криптособытий, разворачивающихся в Париже на этой неделе, помимо громкого Ethereum EthCC, также привлекает внимание DeFi Security Summit 2023. На этом саммите менеджер региональной службы безопасности OpenZeppelin в регионе EMEA Феликс выступил с речью на саммите DeFi Security Summit 2023. BlockBeats собрал и перевел ее для вас следующим образом:
Привет, я Феликс из OpenZeppelin. Возможно, вы знаете, что мы предоставляем библиотеку безопасности для смарт-контрактов, но наши услуги выходят далеко за рамки этого и включают в себя аудит, мониторинг и многие другие аспекты. Тема, которую я хочу обсудить с вами сегодня, — тестирование.
Сейчас перед нами стоит важный вопрос: если мы добьемся 100%-го покрытия тестами, действительно ли мы добьемся безопасности? В случае приобретения, является ли это ограниченной или существенной безопасностью? На этот вопрос я постараюсь ответить в сегодняшней беседе. Однако, прежде чем мы углубимся в этот вопрос, давайте сделаем шаг назад и ответим на вопрос: зачем мы тестируем?
Вообще говоря, цель тестирования такова: вы можете захотеть проверить, реализует ли ваша кодовая база определенную функцию, или вы можете ожидать, что она будет иметь эту функцию.
Это первоначальная цель тестирования, но если вы копнете немного глубже, вы обнаружите, что тестирование имеет и другие цели. Возможно, вы захотите провести не только модульное тестирование, но и интеграционное или сквозное тестирование. Эти тесты на самом деле имеют «описательные» свойства. Таким образом, вы можете четко видеть, как выглядит обычный путь работы вашей базы кода и как потенциальные конечные пользователи будут взаимодействовать с вашей базой кода. Это «описательное» свойство также является его частью. Однако действительно ли это помогает безопасности?
Мы надеемся, что это повысит безопасность. Однако на этом слайде мы не можем ответить на этот вопрос. Итак, давайте продолжим и вернемся к этому вопросу позже. Теперь поговорим о качестве тестов. Со временем вы, возможно, захотите завершить тестирование. Итак, у нас есть множество различных показателей качества.
Первая метрика — «функциональность», то есть тестовое покрытие базы кода. Обычно это выражается как покрытие линии или покрытие филиала. Это хорошее эталонное значение. Мы предположили, что в нашей тестовой выборке это число достигло 100%, и с этим мы справились неплохо.
«Описательный» означает, что у вас есть несколько интересных тестовых примеров, не просто очень маленьких модульных тестов, а очень интересных сквозных тестовых примеров. Теперь снова возникает вопрос: нужна ли нам дополнительная метрика или мы случайно достигли идеальной безопасности? Давайте посмотрим на небольшой пример: вот очень маленький токен ERC20, который я написал:
Как видно в верхней части слайда, 100% тестовое покрытие гарантирует Foundry (фреймворк Solidity). Как вы можете видеть из нижней половины слайда, этот токен имеет три варианта использования: чеканка, сжигание и передача. Все они работают и рассматриваются в этом тестовом примере. По сути, мы делаем хорошую работу с точки зрения «функциональности» и «наглядности», так мы в безопасности?
Нет, существует уязвимость открытого сжигания, и вы можете уничтожить токены любого пользователя. Это критическая уязвимость с безопасностью почти 0%. Нужно это исправить, в таком виде его нельзя развернуть. Так чего же не хватает?
Приведенный выше тестовый пример отсутствует. В синтаксисе Foundry, если имя функции начинается с «провал теста», это в значительной степени означает, что она проверяет конкретный случай сбоя. Типичный тест может проверить, способен ли произвольный адрес уничтожить 1000 монет другого пользователя. Очевидно, вы надеетесь, что этого не произойдет, поэтому пишете этот отрицательный тест. Это всего лишь простой пример, давайте рассмотрим общие принципы.
Когда люди говорят, что проводят тестирование, большая часть того, что мы обычно видим, попадает в левую категорию. Они проводят функциональное тестирование и фокусируются на покрытии. Это действительно часть теста, и сделана она очень хорошо, но напрямую с безопасностью не связана. Если вы хотите провести тестирование безопасности, вам нужно посмотреть направо.
Вы должны спросить себя, адекватно ли я протестировал функциональность своего приложения? Например, в случае несанкционированных функций я действительно проверял, что какой-либо адрес не может взаимодействовать с контрактом определенным образом? Поэтому тестирование осведомленности приложений — это то, что мы здесь называем тестированием безопасности.
Теперь я хочу сделать шаг назад и задуматься над другим вопросом: как работает тестирование в теории и на практике?
Теоретические цифры, предоставленные IBM, предполагают, что нам следует вкладывать значительные средства в тестирование, поскольку оно окупится в реальном выражении. Стоимость будет относительно низкой, если вы обнаружите проблемы на ранней стадии, на этапе проектирования, внедрения или этапа специального тестирования. Однако на этапе развертывания затраты могут резко возрасти. Это относится не только к блокчейн-системам: в этом случае число «100», которое вы видите, может быть дополнительно увеличено на TVL протокола.
Этот принцип применим к любой программной системе. Итак, теоретически каждый должен тестировать как можно лучше, потому что экономические принципы ясно говорят нам, что это окупится. Но на практике тестирование — занятие не из гламурных. Тестирование — это не «круто». Никто не говорит: «Я очень увлечен тестированием качества, я тестировщик». Все «крутые» вещи в основном посвящены хакерам. Конечно, быть взломанным — это плохо для вашего протокола. Но взлом — это «круто», а тестирование — необходимая, но непопулярная задача.
Так как же нам решить эту проблему? Вот мой секрет, как сделать тестирование интересным: относитесь к взлому как к части теста.
Чтобы провести действительно хорошее тестирование безопасности, нам нужно начать с «пока true», потому что этот цикл можно повторять бесконечно. Ваша цель — создать совершенно новую уязвимость POC, которая попытается атаковать разрабатываемый вами протокол. Вы можете убедиться, что это не работает, или обнаружить что-то, что необходимо исправить. Затем вы можете интегрировать это как тестовый пример в свой набор тестов безопасности.
Вы можете сделать тестирование более увлекательным, применив хакерский образ мышления к своей повседневной деятельности. Знаете, это не просто юнит-тест или скучный тест, это типичный курс колледжа. Такое тестирование безопасности больше похоже на современное применение хакерского мышления: оно просто применяется к артефакту, который можно включить в ваш набор тестов.
Это хорошая теория, но теперь нам нужно добавить немного практической точки зрения. Давайте посмотрим, какие проекты в этом году имеют уязвимости на уровне кода. Здесь я говорю не об ошибке низкого уровня, такой как утечка закрытого ключа, а об ошибке в коде. Если бы был использован описанный выше метод проверки, инцидент кражи можно было бы предотвратить. Учитывая, что уже в этом году украдено 250 миллионов долларов, я думаю, что есть веские аргументы, которые могли бы подтолкнуть к интеграции такого рода тестирования безопасности в наборы тестов.
Если вы принимаете решения, вы, вероятно, не захотите запоминать все детали и вам нужен простой критерий. Подсчитайте количество интересных тестовых случаев в вашем наборе тестов на основе доказательства концептуальной уязвимости и используйте это в качестве показателя для тестирования безопасности. Как правило, 100% тестовое покрытие предназначено для функциональных тестов. Это не имеет никакого отношения к безопасности. Если вы хотите провести тестирование безопасности, вам следует протестировать несуществующие части. Хорошее проведение тестирования безопасности требует принятия хакерского мышления и фактического включения POC-уязвимостей в состав набора тестов.
К сожалению, это не панацея. Вы можете начать это как часть своего проекта, а затем в идеале связаться со своим партнером по безопасности для дальнейшего улучшения этого подхода к тестированию.
