Я просто хочу поділитися проблемою безпеки смарт-контрактів, яку багато розробників все ще ігнорують — атакою reentrancy. Якщо ви створюєте смарт-контракт на Solidity, це те, що вам обов’язково потрібно зрозуміти.



Найпростіше, reentrancy трапляється, коли один контракт викликає інший контракт, і цей контракт може викликати назад початковий контракт під час його виконання. Уявіть, у вас є ContractA з 10 Ether, і ContractB надсилає туди 1 Ether. Коли ContractB знімає гроші, ContractA перевіряє, чи баланс більший за 0, і якщо так — відправляє Ether назад. Але якщо у ContractB є fallback-функція (функція резерву), вона може викликати знову функцію зняття у ContractA, поки ця ще не завершилася. Результат? Баланс ContractB все ще фіксується як 1 Ether, тому він отримає ще 1 Ether, і так далі, доки ContractA не буде виснажений.

Як працює ця атака? Зловмисник потребує двох речей: функції attack() для початку, і fallback-функції для повторного виклику функції зняття. Fallback-функція — це спеціальна зовнішня функція без імені, без параметрів, яку будь-хто може активувати, викликавши неіснуючу функцію, не передавши дані або надіславши Ether без даних.

Ось конкретний приклад: контракт EtherStore має функцію deposit() для збереження балансу і функцію withdrawAll() для зняття всього. Проблема у тому, що withdrawAll() перевіряє баланс, відправляє Ether, а потім оновлює баланс до 0. Це створює вразливість для атаки reentrancy.

Як захиститися? Ось три способи.

Перший — використання модифікатора noReentrant. Ідея дуже проста: блокувати контракт під час виконання функції. Якщо хтось спробує викликати цю функцію знову, перевірка блокування не пропустить. Блокування відкриється лише після завершення функції. Модифікатор — це особливий тип функції, що дозволяє додати умови до інших функцій без переписування всієї логіки.

Другий — застосування шаблону Check-Effect-Interaction. Замість того, щоб спочатку перевіряти умови, надсилати гроші, а потім оновлювати баланс, краще зробити навпаки: перевірити, оновити баланс одразу (до відправки Ether), і лише потім взаємодіяти з зовнішніми контрактами. Таким чином, навіть якщо станеться reentrancy, баланс вже оновлений до 0, і зловмисник не зможе вивести додаткові кошти.

Третій — якщо у вашому проекті багато взаємодіючих контрактів, використовуйте GlobalReentrancyGuard. Замість блокування окремої функції, ви блокуватимете всю систему за допомогою змінної стану, збереженої у окремому контракті. Коли викликається будь-яка функція у будь-якому з контрактів, система перевіряє, чи вона не заблокована. Якщо так — транзакція відхиляється. Це особливо корисно, коли у вас є контракти, наприклад, ScheduledTransfer, що надсилає гроші до AttackTransfer — GlobalReentrancyGuard запобігатиме всім ланцюгам атак reentrancy.

Плюс цих трьох методів у тому, що їх можна комбінувати залежно від ситуації. Важлива функція? Використовуйте noReentrant. Багато схожих функцій? Застосовуйте Check-Effect-Interaction. Весь складний проект? Впроваджуйте GlobalReentrancyGuard. Глибше розуміння reentrancy і способів його запобігання допоможе вам створювати більш безпечні смарт-контракти.
Переглянути оригінал
Ця сторінка може містити контент третіх осіб, який надається виключно в інформаційних цілях (не в якості запевнень/гарантій) і не повинен розглядатися як схвалення його поглядів компанією Gate, а також як фінансова або професійна консультація. Див. Застереження для отримання детальної інформації.
  • Нагородити
  • Прокоментувати
  • Репост
  • Поділіться
Прокоментувати
Додати коментар
Додати коментар
Немає коментарів
  • Популярні активності Gate Fun

    Дізнатися більше
  • Рин. кап.:$2.24KХолдери:0
    0.00%
  • Рин. кап.:$2.23KХолдери:1
    0.00%
  • Рин. кап.:$2.24KХолдери:1
    0.00%
  • Рин. кап.:$0.1Холдери:0
    0.00%
  • Рин. кап.:$2.27KХолдери:2
    0.07%
  • Закріпити