Атаки повторного входу представляють одну з найзначніших загроз безпеки в розробці смарт-контрактів. Цей технічний аналіз пояснює механіку, що стоїть за вразливостями повторного входу, і надає всебічні стратегії захисту для захисту ваших контрактів.
Що таке атака повторного входу?
Рекурсія відбувається, коли функцію в смарт-контракті можна перервати під час її виконання та викликати знову до того, як перше викликане завершиться. Технічними термінами, рекурсія експлуатує контекст виконання смарт-контракту, маніпулюючи потоком управління через зовнішні виклики.
Коли Контракт A взаємодіє з Контрактом B, вразливість виникає через те, що Контракт B може викликати Контракт A, поки виконання Контракту A ще триває. Цей рекурсивний шаблон викликів може бути використаний для маніпуляції станом контракту та виведення коштів.
Механіка атак: Як працює повторний вхід
Розгляньте сценарій з двома контрактами:
Контракт A: Вразливий контракт, що утримує 10 ETH
Контракт B: Зловмисний контракт з 1 ETH, депонованим в Контракті A
Потік атаки слідує цій схемі:
Контракт B викликає функцію withdraw() у Контракті A
Контракт A перевіряє, що баланс Контракту B більший за 0 (пройдено перевірку)
Контракт A надсилає 1 ETH до Контракту B перед оновленням свого запису балансу
Передача ETH викликає резервну функцію Контракту B
Усередині функції резервного копіювання Контракт B знову викликає функцію виведення Контракту A ()
Оскільки Контракт A ще не оновив баланс Контракту B, перевірка проходить знову
Контракт A відправляє ще один ETH до Контракту B
Цей цикл повторюється, поки Контракт A не буде вичерпано кошти
Критична вразливість полягає в порядку виконання Контракту A: він виконує зовнішній виклик (, відправляючи ETH) перед оновленням свого внутрішнього стану (, встановлюючи баланс на нуль).
Три техніки захисту від повторного входу
1. Захист на рівні функції з модифікатором noReentrant
Модифікатор noReentrant реалізує механізм блокування, який запобігає рекурсивному виклику функції:
солідність
// Змінна стану для відстеження повторного входу
bool private locked = false;
// Захищена функція
функція withdraw() публічна noReentrant {
// Логіка функції тут
}
Цей підхід блокує спроби повторного входу, підтримуючи змінну стану на рівні контракту, яка запобігає одночасному виконанню захищених функцій.
2. Перевірка-Ефект-Взаємодія Патерн
Цей шаблон реорганізовує код, щоб слідувати конкретній послідовності операцій:
Перевірте: Підтвердіть умови (, наприклад, баланс > 0)
Ефект: Оновлення змінних стану (, наприклад, встановити баланс = 0)
Взаємодія: Виконати зовнішні виклики (, наприклад, перевести ETH)
Порівняння вразливого та захищеного коду:
Уразливий:
солідність
функція withdraw() зовнішня {
uint bal = balances[msg.sender];
require(bal > 0);
// Взаємодія перед Ефектом (vulnerable)
(bool відправлено, ) = msg.sender.call{value: bal}("");
require(sent, "Не вдалося надіслати ефір");
balances[msg.sender] = 0; // Може ніколи не бути досягнуто, якщо станеться повторний виклик
}
Захищено:
солідність
function withdraw() зовнішній {
uint bal = balances[msg.sender];
require(bal > 0);
// Ефект перед взаємодією (secure)
баланси[msg.sender] = 0;
(bool відправлено, ) = msg.sender.call{value: bal}("");
require(sent, "Не вдалося надіслати Ефір");
}
Оновлюючи стан перед зовнішніми взаємодіями, контракт залишається безпечним, навіть якщо зовнішній виклик викликає повторний виклик функції.
3. Захист між контрактами з GlobalReentrancyGuard
Для проектів з кількома взаємодіючими контрактами спільний захист від повторних викликів забезпечує всебічний захист:
солідність
// Центральний контракт для захисту від повторних викликів
contract GlobalReentrancyGuard {
mapping(address = > bool) приватні _status;
// Використання охоронця в контракті
contract ProtectedContract is GlobalReentrancyGuard {
функція protectedFunction() зовнішня {
_beforeNonReentrant();
// Логіка захищеної функції тут
_afterNonReentrant();
}
}
Ця техніка запобігає повторному входу між контрактами, підтримуючи глобальний реєстр станів, який відстежує статус виконання в кількох контрактах у вашій екосистемі.
Кращі практики безпеки
Щоб забезпечити всебічний захист від атак повторного входу:
Застосуйте кілька шарів захисту: Поєднайте патерн перевірки-ефекту-взаємодії з захистом від повторних викликів для максимальної безпеки
Проведіть ретельне тестування: Використовуйте спеціалізовані інструменти, такі як Mythril, для виявлення потенційних вразливостей повторного входу.
Дотримуйтесь встановлених схем: Реалізуйте заходи безпеки послідовно у всіх контрактах вашого проєкту
Використовуйте перевірені залежності: Включайте бібліотеки з перевіреними записами безпеки
Спочатку оновіть баланси: Завжди змінюйте стан перед виконанням зовнішніх викликів або переказів
Здійснюючи ці ці механізми захисту, ви можете ефективно захистити свої смарт-контракти від одного з найнебезпечніших векторів атак у безпеці блокчейну.
Ця сторінка може містити контент третіх осіб, який надається виключно в інформаційних цілях (не в якості запевнень/гарантій) і не повинен розглядатися як схвалення його поглядів компанією Gate, а також як фінансова або професійна консультація. Див. Застереження для отримання детальної інформації.
Смарт-контракт Безпека: Розуміння та запобігання вразливостям повторного входу
Атаки повторного входу представляють одну з найзначніших загроз безпеки в розробці смарт-контрактів. Цей технічний аналіз пояснює механіку, що стоїть за вразливостями повторного входу, і надає всебічні стратегії захисту для захисту ваших контрактів.
Що таке атака повторного входу?
Рекурсія відбувається, коли функцію в смарт-контракті можна перервати під час її виконання та викликати знову до того, як перше викликане завершиться. Технічними термінами, рекурсія експлуатує контекст виконання смарт-контракту, маніпулюючи потоком управління через зовнішні виклики.
Коли Контракт A взаємодіє з Контрактом B, вразливість виникає через те, що Контракт B може викликати Контракт A, поки виконання Контракту A ще триває. Цей рекурсивний шаблон викликів може бути використаний для маніпуляції станом контракту та виведення коштів.
Механіка атак: Як працює повторний вхід
Розгляньте сценарій з двома контрактами:
Потік атаки слідує цій схемі:
Критична вразливість полягає в порядку виконання Контракту A: він виконує зовнішній виклик (, відправляючи ETH) перед оновленням свого внутрішнього стану (, встановлюючи баланс на нуль).
Три техніки захисту від повторного входу
1. Захист на рівні функції з модифікатором noReentrant
Модифікатор noReentrant реалізує механізм блокування, який запобігає рекурсивному виклику функції:
солідність // Змінна стану для відстеження повторного входу bool private locked = false;
// Модифікатор для запобігання повторному входу модифікатор noReentrant() { require(!заблоковано, "Дзвінок повторного входу"); заблоковано = true; _; locked = false; }
// Захищена функція функція withdraw() публічна noReentrant { // Логіка функції тут }
Цей підхід блокує спроби повторного входу, підтримуючи змінну стану на рівні контракту, яка запобігає одночасному виконанню захищених функцій.
2. Перевірка-Ефект-Взаємодія Патерн
Цей шаблон реорганізовує код, щоб слідувати конкретній послідовності операцій:
Порівняння вразливого та захищеного коду:
Уразливий: солідність функція withdraw() зовнішня { uint bal = balances[msg.sender]; require(bal > 0);
}
Захищено: солідність function withdraw() зовнішній { uint bal = balances[msg.sender]; require(bal > 0);
}
Оновлюючи стан перед зовнішніми взаємодіями, контракт залишається безпечним, навіть якщо зовнішній виклик викликає повторний виклик функції.
3. Захист між контрактами з GlobalReentrancyGuard
Для проектів з кількома взаємодіючими контрактами спільний захист від повторних викликів забезпечує всебічний захист:
солідність // Центральний контракт для захисту від повторних викликів contract GlobalReentrancyGuard { mapping(address = > bool) приватні _status;
}
// Використання охоронця в контракті contract ProtectedContract is GlobalReentrancyGuard { функція protectedFunction() зовнішня { _beforeNonReentrant();
}
Ця техніка запобігає повторному входу між контрактами, підтримуючи глобальний реєстр станів, який відстежує статус виконання в кількох контрактах у вашій екосистемі.
Кращі практики безпеки
Щоб забезпечити всебічний захист від атак повторного входу:
Здійснюючи ці ці механізми захисту, ви можете ефективно захистити свої смарт-контракти від одного з найнебезпечніших векторів атак у безпеці блокчейну.