在区块链世界中,以太坊的 ERC20 代币标准是最广为人知的代币标准协议之一。然而,在实现 ERC20 标准的过程中,approve 函数的一些误用可能导致严重的安全漏洞,被称为 ApproveScam。本文将深入探讨 ApproveScam 漏洞的原理、危害以及相应的防范措施。
什么是 ApproveScam 漏洞?
ApproveScam 漏洞源于 ERC20 标准中 approve 函数的误用。approve 函数本身的设计目的是允许代币持有者授权某个地址可以从持有者账户中转移一定数量的代币。但如果持有者授权的金额过大(通常是无限大type(uint256).max),攻击者就可以在未经持有者同意的情况下,从持有者账户中转移走所有代币。
具体来说,一旦 Alice 授权了 Eve 可以无限转移 Alice 账户中的代币,Eve 就可以调用 transferFrom 函数,将 Alice 账户中的所有代币转移到自己的账户中。这就是 ApproveScam 漏洞的核心原理。
// Alice 授权 Eve 可以无限转移自己账户中的代币
ERC20Contract.approve(address(eve), type(uint256).max);
// Eve 利用授权转移 Alice 账户中的所有代币
ERC20Contract.transferFrom(address(alice), address(eve), 1000);
ApproveScam 造成的危害
ApproveScam 漏洞虽然原理简单,但造成的损失却可能是灾难性的。一旦用户轻易的给某个地址授权,那么攻击者可以在用户不知情的情况下,轻易转走其账户中的所有代币。
除此之外,ApproveScam 漏洞还可能被滥用于其他诸如洗钱等违法犯罪活动中。总的来说,ApproveScam 是一个严重的安全隐患,需要开发者和用户高度重视。
ApproveScam 漏洞攻击演示
我们有如下遵循 ERC20 协议的 MyToken 合约,账户Alice(0x5B3…dC4) 被 Eve(0xAb8…cb2) 的钓鱼网站恶意授权导致损失所有的 Token。
// SPDX-License-Identifier: MIT
// Compatible with OpenZeppelin Contracts ^5.0.0
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
contract MyToken is ERC20, Ownable {
constructor()
ERC20("MyToken", "MTK")
Ownable(msg.sender)
{}
function mint(address to, uint256 amount) public onlyOwner {
_mint(to, amount);
}
function approve(address spender, uint256 value) public virtual override returns (bool) {
address owner = _msgSender();
_approve(owner, spender, value);
return true;
}
}
1.账户Alice(0x5B3…dC4) 部署 MyToken 合约,并为自己铸造了 1000 枚 Token。
2.手动调用 approve 函数模拟账户 Alice(0x5B3…dC4) 授权黑客 Eve(0xAb8…cb2) 无限量的代币,授权数量 115792089237316195423570985008687907853269984665640564039457584007913129639935 为 type(uint256).max,对应的授权页面为第 2 张图。不建议无限量的授权额度,即使这样做可以节省 gas 费(不用每次交互都发起授权交易)。
3.调用 transferFrom 函数,将账户 Alice(0x5B3…dC4) 的资产全部转移到 Eve(0xAb8…cb2) 控制的账户 (0x4B2…2db)中,执行成功后,我们会发现黑客账户(0x4B2…2db)有 1000 个 Token。
如何防范 ApproveScam 漏洞
防范 ApproveScam 漏洞的最好方式是谨慎使用 approve 函数,尤其是在授权金额时。应当遵循以下原则:
1.只在必要时才调用 approve 函数,不要滥用或过度使用。
2.授权金额应当根据实际需求设置,例如approve(spender, amount)而非approve(spender, type(uint256).max)。
3.在功能实现结束后,应及时撤销之前的授权,即approve(spender, 0)。
4.在智能合约开发阶段,彻底检查 approve 函数的使用,防范 ApproveScam 漏洞。
总之,ApproveScam 漏洞是 ERC20 标准一个需要警惕的安全隐患,需要开发者和用户共同重视,不要盲目签名,避免资产受损失。