Скануйте, щоб завантажити додаток Gate
qrCode
Більше варіантів завантаження
Не нагадувати сьогодні

Атака повторного входу: Чому Смарт-контракти продовжують бути знищеними ( І як це зупинити )

Швидка версія: Рекурсія - це як якщо хакер знову телефонує вам, поки ви ще передаєте їм гроші — вони висмоктують ваш гаманець ще до того, як транзакція закінчиться.

Ось жорстка правда: понад $100M було втрачено через експлойти повторного входу. Найвідоміший? Хак DAO (2016) викрав $50M в ETH, експлуатуючи цю саму вразливість.

Як працює атака (Використовуючи реальну логіку коду)

Уявіть, що ContractA має 10 ETH, а ContractB має баланс у 1 ETH, збережений всередині нього.

Коли ContractB викликає withdrawAll(), ось що повинно статися:

  1. Перевірте баланс > 0 ✓
  2. Відправити ETH назад ✓
  3. Оновити баланс до 0 ✓

Але ось де це ламається: Зловмисник експлуатує порядок виконання.

Потік експлуатації:

  • Зловмисник викликає attack() → що викликає withdrawAll() на ContractA
  • ContractA надсилає 1 ETH і викликає функцію резервного копіювання атакуючого ()
  • Перед оновленням балансу до 0, fallback() негайно знову викликає withdrawAll()
  • ContractA перевіряє: “Чи баланс > 0?” ТАК (, тому що він ще не оновлений!)
  • Відправляє ще 1 ETH → знову викликає fallback()
  • Цей цикл триває, поки ContractA повністю не буде вичерпано

Ключове спостереження: Оновлення балансу відбувається ПІСЛЯ переказу ETH. Це вікно вразливості.

Три стратегії захисту

1. Модифікатор nonReentrant (Одинарний захист функції)

Заблокувати функцію під час її виконання. Повторний вхід не дозволено: солідність модифікатор nonReentrant { require(!locked, “Немає повторного входу”); заблоковано = true; _; locked = false; }

Простий, але захищає лише одну функцію за раз.

2. Шаблон Перевірок-Ефектів-Взаємодій (Багатофункціональний Захист)

Це зміна гри:

  • Перевірки: Перевірити умови (balance > 0)
  • Ефекти: Оновити стан (баланс = 0) ← Перемістіть це перед відправкою ETH
  • Взаємодії: Відправити ETH

Неправильне замовлення:

require(баланс > 0); → відправити ETH → баланс = 0; // Занадто пізно!

Правильний порядок:

require(balance > 0); → баланс = 0; // Оновити ПЕРШИЙ → відправити ETH // Потім взаємодіяти

Тепер, навіть якщо fallback() повторно входить, баланс вже 0. Атака не вдається.

3. GlobalReentrancyGuard (Захист міжконтракту)

Для складних систем з кількома взаємодіючими контрактами використовуйте централізований охоронний контракт, який відстежує стан блокування в усіх контрактах. Коли ContractA викликає ContractB, охоронець це фіксує - якщо ContractB намагається знову викликати систему перед поверненням, охоронець блокує це.

Чому це важливо

Рекурсія — це не лише проблема Solidity — це проблема дизайну. Щоразу, коли ви надсилаєте ETH або викликаєте зовнішні функції, ви передаєте контроль ненадійному коду. Функція резервного копіювання зловмисника виконується в контексті ВАШОГО контракту.

Дані: Chainalysis виявила, що ~60% високовартісних експлойтів у 2023-2024 роках були пов'язані з повторними входами або подібними патернами. Провідні проекти, такі як Yearn, Curve та Balancer, мали проблеми з повторними входами.

Основний висновок: Використовуйте Checks-Effects-Interactions за замовчуванням. Додавайте nonReentrant там, де це необхідно. Для багатоконтрактних систем реалізуйте GlobalReentrancyGuard. Втрачені $100M+ могли б бути збережені завдяки цим базовим шаблонам.

Слідкуйте за @TheBlockChainer для більш глибоких досліджень безпеки Web3.

ETH-1.62%
CRV7.26%
BAL-3.51%
Переглянути оригінал
Ця сторінка може містити контент третіх осіб, який надається виключно в інформаційних цілях (не в якості запевнень/гарантій) і не повинен розглядатися як схвалення його поглядів компанією Gate, а також як фінансова або професійна консультація. Див. Застереження для отримання детальної інформації.
  • Нагородити
  • Прокоментувати
  • Репост
  • Поділіться
Прокоментувати
0/400
Немає коментарів
  • Закріпити