Я витратив безліч годин на налагодження експлойтів контрактів, і дозвольте мені сказати вам – атаки повторного входу є тихими вбивцями смартконтрактів. Вони вводять в оману своєю простотою, але є руйнівно ефективними. Давайте розглянемо, що це таке і як їх зупинити, перш ніж вони витратять ваші кошти.
Коли я вперше зіткнувся з вразливістю повторного входу, я втратив години сну, намагаючись зрозуміти, як хтось міг би експлуатувати таку, здавалося б, безневинну частину коду. Концепція неймовірно проста: один контракт може викликати інший до завершення першого виконання.
Уявіть собі таке: ContractA має 10 ETH, а ContractB вніс 1 ETH у нього. Коли ContractB знімає свої кошти, ContractA відправляє ETH, перш ніж оновити баланс B до нуля. Ця маленька помилка в послідовності створює величезну вразливість безпеки.
Що відбувається? Функція зворотного виклику зловмисного контракту негайно викликає withdraw() знову, і оскільки баланс ще не був оновлений, вона знову проходить перевірку балансу! Цей цикл повторюється, поки ContractA не буде повністю спустошено. Чорт забирай, розумно, чи не так?
Ось як зловмисник використовує це в коді:
// Атакувати контракт викликає withdraw()
// ContractA надсилає ETH, що активує fallback()
// fallback() знову викликає withdraw() перед оновленнями балансу
// Промийте і повторіть, поки всі кошти не будуть вкрадені
Я бачив, як проекти втрачають мільйони, тому що не розуміють цього простого вектору атаки. Мене це дратує, як багато розробників досі роблять цю новачкову помилку.
Три техніки для захисту ваших смартконтрактів
Модифікатор nonReentrant
Це блокує контракт під час виконання, запобігаючи повторному входу в будь-яку функцію, позначену цим модифікатором. Просто, але ефективно.
// БЕЗПЕЧНО
require(balance > 0);
balance = 0; // Оновіть стан ДО зовнішніх взаємодій
send(ether);
Завжди оновлюйте свій стан перед відправкою ETH або токенів!
GlobalReentrancyGuard
Для проектів з кількома взаємодіючими контрактами це забезпечує захист по всій вашій екосистемі контрактів, використовуючи спільний механізм блокування.
Ці техніки не є лише академічними - вони врятували безліч проектів від повного фінансового краху.
Занадто багато розробників все ще вважають, що "це не трапиться з ними" і ігнорують ці заходи захисту. Не будьте цією людиною. Кожна окрема функція, що надсилає ETH або токени, має реалізовувати принаймні один з цих механізмів захисту.
Пам'ятайте, у розробці смартконтрактів параноя є функцією, а не помилкою. Відсутність однієї захисної міри може коштувати всього.
Ця сторінка може містити контент третіх осіб, який надається виключно в інформаційних цілях (не в якості запевнень/гарантій) і не повинен розглядатися як схвалення його поглядів компанією Gate, а також як фінансова або професійна консультація. Див. Застереження для отримання детальної інформації.
Атака повторного входу: розуміння та запобігання цій вразливості смарт-контракту
Я витратив безліч годин на налагодження експлойтів контрактів, і дозвольте мені сказати вам – атаки повторного входу є тихими вбивцями смартконтрактів. Вони вводять в оману своєю простотою, але є руйнівно ефективними. Давайте розглянемо, що це таке і як їх зупинити, перш ніж вони витратять ваші кошти.
Коли я вперше зіткнувся з вразливістю повторного входу, я втратив години сну, намагаючись зрозуміти, як хтось міг би експлуатувати таку, здавалося б, безневинну частину коду. Концепція неймовірно проста: один контракт може викликати інший до завершення першого виконання.
Уявіть собі таке: ContractA має 10 ETH, а ContractB вніс 1 ETH у нього. Коли ContractB знімає свої кошти, ContractA відправляє ETH, перш ніж оновити баланс B до нуля. Ця маленька помилка в послідовності створює величезну вразливість безпеки.
Що відбувається? Функція зворотного виклику зловмисного контракту негайно викликає withdraw() знову, і оскільки баланс ще не був оновлений, вона знову проходить перевірку балансу! Цей цикл повторюється, поки ContractA не буде повністю спустошено. Чорт забирай, розумно, чи не так?
Ось як зловмисник використовує це в коді:
// Атакувати контракт викликає withdraw() // ContractA надсилає ETH, що активує fallback() // fallback() знову викликає withdraw() перед оновленнями балансу // Промийте і повторіть, поки всі кошти не будуть вкрадені
Я бачив, як проекти втрачають мільйони, тому що не розуміють цього простого вектору атаки. Мене це дратує, як багато розробників досі роблять цю новачкову помилку.
Три техніки для захисту ваших смартконтрактів
Модифікатор nonReentrant
Це блокує контракт під час виконання, запобігаючи повторному входу в будь-яку функцію, позначену цим модифікатором. Просто, але ефективно.
Шаблон Перевірки-Ефекти-Взаємодії
Це мій особистий фаворит. Замість:
// ВРАЖАЮЧИЙ require(balance > 0); надіслати(ефір); залишок = 0;
Зробіть це:
// БЕЗПЕЧНО require(balance > 0); balance = 0; // Оновіть стан ДО зовнішніх взаємодій send(ether);
Завжди оновлюйте свій стан перед відправкою ETH або токенів!
GlobalReentrancyGuard
Для проектів з кількома взаємодіючими контрактами це забезпечує захист по всій вашій екосистемі контрактів, використовуючи спільний механізм блокування.
Ці техніки не є лише академічними - вони врятували безліч проектів від повного фінансового краху.
Занадто багато розробників все ще вважають, що "це не трапиться з ними" і ігнорують ці заходи захисту. Не будьте цією людиною. Кожна окрема функція, що надсилає ETH або токени, має реалізовувати принаймні один з цих механізмів захисту.
Пам'ятайте, у розробці смартконтрактів параноя є функцією, а не помилкою. Відсутність однієї захисної міри може коштувати всього.