Смарт-контракт Безопасность: Понимание и предотвращение уязвимостей повторного входа

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

Что такое атака повторного входа?

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

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

Механика атак: Как работает повторный вход

Рассмотрим сценарий с двумя контрактами:

  • Контракт A: Уязвимый контракт, хранящий 10 ETH
  • Контракт B: Зловредный контракт с 1 ETH, внесенным в Контракт A

Поток атаки следует этой схеме:

  1. Контракт B вызывает функцию withdraw() в Контракте A
  2. Контракт A проверяет, что баланс Контракта B больше 0 (прошел проверку)
  3. Контракт A отправляет 1 ETH на контракт B перед обновлением своей записи баланса
  4. Перевод ETH вызывает функцию обратного вызова Контракта B
  5. Внутри функции резервирования Контракт B снова вызывает функцию вывода Контракта A ()
  6. Поскольку Контракт A еще не обновил баланс Контракта B, проверка проходит снова
  7. Контракт A отправляет еще один ETH в Контракт B
  8. Этот цикл повторяется, пока Контракт A не будет исчерпан средств.

Критическая уязвимость заключается в порядке выполнения Контракта A: он выполняет внешний вызов (, отправляя ETH) до обновления своего внутреннего состояния (, устанавливая баланс равным нулю ).

Три техники защиты от повторного входа

1. Защита на уровне функции с модификатором noReentrant

Модификатор noReentrant реализует механизм блокировки, который предотвращает рекурсивный вызов функции:

солидность // Переменная состояния для отслеживания повторного входа bool private locked = false;

// Модификатор для предотвращения повторного входа модификатор noReentrant() { require(!locked, "Повторный звонок"); заблокирован = true; _; заблокировано = ложь; }

// Защищенная функция функция withdraw() публичная noReentrant { // Логика функции здесь }

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

2. Паттерн проверки-эффекта-взаимодействия

Эта структура перерабатывает код, чтобы следовать определенной последовательности операций:

  1. Проверьте: Проверьте условия (, например, баланс > 0)
  2. Эффект: Обновить переменные состояния (, например, установить баланс = 0)
  3. Взаимодействие: Выполняйте внешние вызовы (, например, переводите ETH )

Сравнение уязвимого и защищенного кода:

Уязвимый: солидность функция withdraw() внешний { uint bal = balances[msg.sender]; require(bal > 0);

// Взаимодействие перед Эффектом (уязвимый)
(bool отправлено, ) = msg.sender.call{value: bal}("");
require(sent, "Не удалось отправить Эфир");

balances[msg.sender] = 0; // Может никогда не быть достигнуто, если произойдет повторный вход

}

Защищено: солидность функция withdraw() внешний { uint bal = balances[msg.sender]; require(bal > 0);

// Эффект перед взаимодействием (secure)
balances[msg.sender] = 0;

(bool отправлено, ) = msg.sender.call{value: bal}("");
require(отправлено, "Не удалось отправить Эфир");

}

Обновляя состояние перед внешними взаимодействиями, контракт остается безопасным, даже если внешний вызов инициирует повторный вызов функции.

3. Защита между контрактами с GlobalReentrancyGuard

Для проектов с несколькими взаимодействующими контрактами общий защитник от повторного входа обеспечивает всестороннюю защиту:

солидность // Центральный контракт для защиты от повторных вызовов контракт GlobalReentrancyGuard { mapping(address => bool) частный _status;

функция _beforeNonReentrant() внутренний {
    require(_status[msg.sender] == false, "ReentrancyGuard: reentrant call");
    _status[msg.sender] = true;
}

функция _afterNonReentrant() внутренний { 
    _status[msg.sender] = false;
}

}

// Использование охранника в контракте контракт ProtectedContract is GlobalReentrancyGuard { функция protectedFunction() внешняя { _beforeNonReentrant();

    // Защищенная логика функции здесь
    
    _afterNonReentrant();
}

}

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

Лучшие практики безопасности

Чтобы обеспечить комплексную защиту от атак повторного входа:

  1. Примените несколько слоев защиты: Сочетайте шаблон проверки-эффекта-взаимодействия с защитой от повторного входа для максимальной безопасности
  2. Проведите тщательное тестирование: Используйте специализированные инструменты, такие как Mythril, для обнаружения потенциальных уязвимостей повторного входа.
  3. Следуйте установленным шаблонам: Последовательно внедряйте меры безопасности во всех контрактах вашего проекта
  4. Используйте проверенные зависимости: Включайте библиотеки, прошедшие аудит, с проверенной историей безопасности.
  5. Сначала обновите балансы: Всегда изменяйте состояние перед выполнением внешних вызовов или переводов

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

ETH2.11%
Посмотреть Оригинал
На этой странице может содержаться сторонний контент, который предоставляется исключительно в информационных целях (не в качестве заявлений/гарантий) и не должен рассматриваться как поддержка взглядов компании Gate или как финансовый или профессиональный совет. Подробности смотрите в разделе «Отказ от ответственности» .
  • Награда
  • комментарий
  • Репост
  • Поделиться
комментарий
0/400
Нет комментариев
  • Закрепить