Перейти к основному контенту

Руководство по безопасности смарт-контрактов

solidity
смарт-контракты
безопасность
Средний уровень
Trailofbits
6 сентября 2020 г.
4 минут на чтение

Следуйте этим высокоуровневым рекомендациям для создания более безопасных смарт-контрактов.

Рекомендации по проектированию

Проектирование контракта следует обсудить заранее, до написания хотя бы одной строчки кода.

Документация и спецификации

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

  • Описание системы простым языком, объясняющее, что делают контракты, и любые допущения относительно кодовой базы.
  • Схемы и архитектурные диаграммы, включая взаимодействия контрактов и машину состояний системы. Принтеры Слизер (opens in a new tab) могут помочь в генерации этих схем.
  • Тщательная документация кода, для Solidity можно использовать формат NatSpec (opens in a new tab).

Вычисления ончейн и офчейн

  • Держите как можно больше кода офчейн. Оставляйте ончейн-слой небольшим. Предварительно обрабатывайте данные с помощью кода офчейн таким образом, чтобы проверка ончейн была простой. Вам нужен упорядоченный список? Отсортируйте список офчейн, а затем только проверьте его порядок ончейн.

Возможность обновления

Мы обсуждали различные решения для обновления в нашем блоге (opens in a new tab). Сделайте осознанный выбор в пользу поддержки возможности обновления или отказа от нее до написания какого-либо кода. Это решение повлияет на то, как вы структурируете свой код. В целом, мы рекомендуем:

  • Отдавать предпочтение миграции контрактов (opens in a new tab), а не возможности обновления. Системы миграции имеют много тех же преимуществ, что и обновляемые, но без их недостатков.
  • Использовать паттерн разделения данных вместо паттерна delegatecallproxy. Если в вашем проекте есть четкое разделение абстракций, возможность обновления с использованием разделения данных потребует лишь нескольких корректировок. Использование delegatecallproxy требует глубоких знаний EVM и сопряжено с высоким риском ошибок.
  • Документировать процедуру миграции/обновления до развертывания. Если вам придется реагировать в стрессовой ситуации без каких-либо инструкций, вы наделаете ошибок. Заранее напишите процедуру, которой следует придерживаться. Она должна включать:
    • Вызовы, которые инициируют новые контракты
    • Где хранятся ключи и как получить к ним доступ
    • Как проверить развертывание! Разработайте и протестируйте скрипт, выполняемый после развертывания.

Рекомендации по реализации

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

Композиция функций

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

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

Наследование

  • Сохраняйте наследование управляемым. Наследование следует использовать для разделения логики, однако ваш проект должен стремиться к минимизации глубины и ширины дерева наследования.
  • Используйте принтер наследования (opens in a new tab) Слизер для проверки иерархии контрактов. Принтер наследования поможет вам оценить размер иерархии.

События

  • Ведите лог всех важных операций. События помогут отлаживать контракт во время разработки и отслеживать его после развертывания.

Избегайте известных подводных камней

Зависимости

  • Используйте хорошо протестированные библиотеки. Импорт кода из хорошо протестированных библиотек снизит вероятность написания кода с ошибками. Если вы хотите написать контракт ERC-20, используйте ОпенЗеппелин (opens in a new tab).
  • Используйте менеджер зависимостей; избегайте копирования и вставки кода. Если вы полагаетесь на внешний источник, вы должны поддерживать его в актуальном состоянии в соответствии с оригиналом.

Тестирование и верификация

  • Пишите тщательные модульные тесты. Обширный набор тестов имеет решающее значение для создания высококачественного программного обеспечения.
  • Пишите пользовательские проверки и свойства для Слизер (opens in a new tab), Эхидна (opens in a new tab) и Мантикора (opens in a new tab). Автоматизированные инструменты помогут убедиться в безопасности вашего контракта. Ознакомьтесь с остальной частью этого руководства, чтобы узнать, как писать эффективные проверки и свойства.
  • Используйте crytic.io (opens in a new tab). Crytic интегрируется с GitHub, предоставляет доступ к приватным детекторам Слизер и запускает пользовательские проверки свойств от Эхидна.

Solidity

  • Отдавайте предпочтение Solidity 0.5 вместо 0.4 и 0.6. По нашему мнению, Solidity 0.5 более безопасен и имеет лучшие встроенные практики, чем 0.4. Версия Solidity 0.6 оказалась слишком нестабильной для продакшена и требует времени для доработки.
  • Используйте стабильный релиз для компиляции; используйте последний релиз для проверки предупреждений. Убедитесь, что в вашем коде нет проблем, о которых сообщает последняя версия компилятора. Однако Solidity имеет быстрый цикл выпуска и историю ошибок компилятора, поэтому мы не рекомендуем использовать последнюю версию для развертывания (см. рекомендации по версии solc (opens in a new tab) от Слизер).
  • Не используйте встроенный ассемблер. Ассемблер требует глубоких знаний EVM. Не пишите код для EVM, если вы не освоили желтую книгу.

Рекомендации по развертыванию

После того как контракт был разработан и развернут:

  • Мониторьте свои контракты. Следите за логами и будьте готовы отреагировать в случае компрометации контракта или кошелька.
  • Добавьте свою контактную информацию в blockchain-security-contacts (opens in a new tab). Этот список помогает третьим лицам связаться с вами в случае обнаружения уязвимости в системе безопасности.
  • Обеспечьте безопасность кошельков привилегированных пользователей. Следуйте нашим лучшим практикам (opens in a new tab), если вы храните ключи в аппаратных кошельках.
  • Имейте план реагирования на инциденты. Учитывайте, что ваши смарт-контракты могут быть скомпрометированы. Даже если в ваших контрактах нет ошибок, злоумышленник может завладеть ключами владельца контракта.