Повторная атака на смарт-контрактыэто общая безопасностьлазейки,Особенно на блокчейне на базе Ethereum.,Он использует недостаток в разработке и реализации смарт-контракта. Суть атаки повторного входа заключается в том, что злоумышленник может существовать на промежуточных этапах транзакции.,т.е. когда смарт-контракт не завершил ожидаемое обновление внутреннего статуса,рекурсия для вызова договорной той же или другой функции.
.call()
или .delegatecall()
Метод переводит деньги на контракт злоумышленника и выполняет код.
Ключом к повторной атаке является то, что злоумышленник может использовать порядок выполнения контракта и время обновления состояния. Чтобы предотвратить этот тип атаки, разработчикам необходимо убедиться, что все обновления внутреннего состояния завершены, прежде чем совершать какие-либо внешние вызовы. Кроме того, используйте .transfer()
и .send()
вместо этого метод .call()
Также может снизить риск, поскольку по умолчанию он ниже. gas лимит, которого может быть недостаточно для выполнения сложного вредоносного кода.
Вероятно, наиболее известен своей работой над The ДАО-атака,Хотя это не совсем повторная атака,Но это показывает, как злоумышленники могут использовать контракт для незаконного получения средств. но,Ниже я приведу упрощенный пример реентерабельной атаки смарт-контракт.,Это часто используется в образовательных и исследовательских сценариях для объяснения концепции повторных атак.
Допустим, у нас есть простой смарт-контракт, который позволяет пользователям вносить и снимать средства:
pragma solidity ^0.8.0;
contract SimpleBank {
mapping(address => uint256) public balances;
function deposit() public payable {
balances[msg.sender] += msg.value;
}
function withdraw(uint256 _amount) public {
if (_amount <= balances[msg.sender]) {
// Это экономит существованиелазейки, поскольку сначала проверяет баланс, а затем вызывает внешний контракт.
(bool success, ) = msg.sender.call{value: _amount}("");
require(success, "Transfer failed.");
balances[msg.sender] -= _amount;
}
}
}
существуют В настоящем договоре,withdraw
Есть уязвимость в функции, которая сначала проверяет, достаточен ли баланс пользователя, затем пытается перевести средства на счет пользователя и, наконец, обновляет баланс в контракте. Если у злоумышленника есть вредоносный контракт, он может перезвонить сразу же после получения средств. SimpleBank
договорной withdraw
функции, поскольку баланс не был обновлен, злоумышленник может выводить средства из контракта неограниченное количество раз до тех пор, пока gas измученный.
Далее злоумышленник договорной Простой пример:
pragma solidity ^0.8.0;
contract Attacker {
address private target;
constructor(address _target) {
target = _target;
}
function attack() public payable {
(bool success, ) = target.call{value: msg.value}("");
require(success, "Attack failed.");
}
fallback() external payable {
// При поступлении средств контракт жертвы немедленно аннулируется.
(bool success, ) = target.call{value: 1 ether}("");
require(success, "Recursive call failed.");
}
}
существуют в контракте этого злоумышленника,fallback
Функция автоматически активируется при получении эфира. Когда злоумышленник звонит attack
функцияи отправить средства жертве контракта,Как только средства поступят,fallback
Функция будет активирована, что вызовет виктимизацию рекурсия договорной withdraw
функцию, чтобы попытаться снова вывести средства.
пожалуйста, обрати внимание,Этот пример предназначен для демонстрации концепции повторных атак.,Не рекомендуется использовать в производственных средах. существовать в реальном мире,Разработчики умной договорной программы принимают многочисленные меры безопасности для предотвращения таких атак.,Например, существует обновление статуса перед внешним вызовом.,Используйте атомарные операции,или Используйте более безопасные переводы, предоставляемые Ethereumфункция .transfer()
и .send()
。
Давайте шаг за шагом проанализируем код договорной атаки, чтобы лучше понять, как он реализует повторную атаку.
Во-первых, вот функция атаки договорной конструкции:
constructor(address _target) {
target = _target;
}
Вот _target
Параметр указывает на адрес смарт-контракта жертвы, о котором мы упоминали выше. SimpleBank
договор. При развертывании контракта атаки вам необходимо указать этот адрес, чтобы контракт атаки знал, какой контракт атаковать.
Далее attack
функция:
function attack() public payable {
(bool success, ) = target.call{value: msg.value}("");
require(success, "Attack failed.");
}
Эта функция получает эфир в качестве параметра (через payable
ключевое слово). Когда вы вызываете эту функцию и отправляете эфир, она переводит деньги на _target
,То есть SimpleBank
договор. Здесь используется низкоуровневый .call()
метод, который может выполнять вызовы произвольных данных, включая передачу эфира.
сейчассуществовать,Вот и ключевая часть,fallback
функция:
fallback() external payable {
// При поступлении средств контракт жертвы немедленно аннулируется.
(bool success, ) = target.call{value: 1 ether}("");
require(success, "Recursive call failed.");
}
существовать Solidity середина,fallback
Функция автоматически выполняется, когда существующий контракт получает данные или эфир без указанного вызова функции. В нашем случае, когда. SimpleBank
Когда контракт пытается вернуть средства злоумышленнику, он фактически называет атаку договорной. fallback
функция.
существовать fallback
Внутри функции контракт злоумышленника немедленно вызывает ее снова. SimpleBank
договорной withdraw
функцию, чтобы попытаться снова вывести средства. потому что SimpleBank
Контракт существует, обновляет баланс только после возврата средств, а это означает, что контракт злоумышленника может продолжать повторять этот процесс до тех пор, пока все эфирные монеты не будут выведены и транзакция злоумышленника не будет завершена. gas одеялоизмученный.
Подводя итог, процесс лечения выглядит следующим образом:
attack
Функционируйте и отправляйте эфир на SimpleBank
договор.SimpleBank
договорной withdraw
Вызывается функция, пытающаяся вернуть деньги злоумышленнику.fallback
Функциясуществовать Контракт злоумышленника сработал, поскольку он получил эфир.fallback
Функция обратного вызова немедленно SimpleBank
договорной withdraw
Функция, повторная попытка вывода денег.Это основной принцип повторных атак. существуют в практическом применении,Контракту злоумышленника может потребоваться некоторая дополнительная логика, чтобы избежать бесконечных циклов.,и обеспечить успешную атаку. также,В современных практиках разработки смарт-контрактов используются более безопасные методы предотвращения подобных атак.,Например, сначала спишите остаток, а затем переведите деньги.,Используется или .transfer()
или .send()
методы, они сразу же генерируют исключение, не продолжая выполнять остальную часть кода.
fallback
ФункциясуществоватьSolidityсмарт-контракт — это особый тип Функции, которая автоматически выполняет существование в следующих ситуациях:
fallback
функциябудет выполнено автоматически。
fallback
функциявстречаодеяловызов。
.call()
метод:Когда в вашем контракте используется низкоуровневый.call()
、.delegatecall()
или.staticcall()
методвызовеще один контракт,Если целевой контракт не возвращает никаких данных,Так Цельдоговорнойfallback
функция将встречаодеялоосуществлять。
Следует отметить, что существует Solidity После версии 0.6.0,fallback
функцияодеялоразделен на две части:fallback
иreceive
。receive
функция Обращайтесь только с чистымEtherприема,Нет случая, когда данные прикрепляются,иfallback
функциязатем справиться сданныеизEtherперениматьилинеизвестныйфункциявызов。это означаетсуществоватьновая версияизSolidityсередина,Если вы хотите заниматься только получением чистого эфира,ты можешь использоватьreceive
функция,Нет необходимости писать тело кода,Он автоматически получит эфир, не делая ничего другого.
Например,простойизreceive
функцияможно определить так:
receive() external payable {}
Это означает, что ваш контракт может получать эфир.,и不встреча触发任何额外издействовать。иодинfallback
функция可能встреча包含更多излогика,Напримериметь дело сперениматьприезжатьизданныеили Выполнить некоторую бизнес-логику。
существуют В примере контракта на атаку, который вы упомянули,fallback
функция Просто воспользовавшисьэтотхарактеристика,Автоматически выполнять и инициироватьрекурсивный вызов для исчерпания целевых договорных средств.