我知道,而且我很容易理解为什么使用tx.origin来检查调用者的身份是很难被攻击的,因为有很多关于这方面的文章,就像这个例子
但在这里,另一个我在文章中找不到的案例是:这种情况下是否存在漏洞?我看不出我们怎么能在这里偷别人的平衡。即使这个函数是从恶意的智能契约中调用的,EOA最终也会得到他的平衡。我知道这段代码意味着一个聪明的契约不可能在这个契约中有一个平衡,这意味着多个sig钱包也不能在这里存储价值,但我不认为这是一个漏洞。
作为记录,这是来自一个小测验,问题是“什么是错的/可以改进的”。
我可以找到的两件事是显式地将可见性设置为平衡(例如public ),并在开始时添加一个require(balance[tx.origin] > 0),如果没有什么可撤回的,则不消耗气体。
contract Test {
mapping(address => uint256) balance;
constructor() {
}
function withdraw() external {
(bool success, ) = tx.origin.call{value: balance[tx.origin]}("");
require(success, "transfer failed");
balance[tx.origin] = 0;
}
function deposit () external payable {
balance[tx.origin] = msg.value;
}
}谢谢
发布于 2022-12-03 11:45:13
我能想到的一个利用是,你可以欺骗另一个聪明的合同,以你的名义存款。
假设有一个保险库合同,它汇集了ETH的存款,然后将它们存入一个创收合同,就像您的Test合同一样。这份合同可以被利用,让它打电话给deposit,然后你取出存款到你的个人钱包。
发布于 2022-12-03 15:28:20
在取回()函数中,tx.origin用于确定调用者的地址。但是,这可能是一个安全漏洞,因为恶意契约可以操纵tx.origin来模拟另一个地址。这意味着恶意契约可能会调用提取()函数,并将属于另一个地址的资金转移给自己。
提高此契约安全性的一种方法是使用msg.sender而不是tx.origin来确定调用方的地址。msg.sender是调用方的实际地址,它不能被恶意契约操纵。
此外,正如您所提到的,最好将余额映射的可见性显式地设置为public,以便其他契约可以访问它。这将允许其他契约检查地址的余额,而不必调用定金()或取款()函数。
最后,正如您所提到的,最好在取回()函数的开头添加一个require()语句,以检查调用方是否有非零余额。如果调用方没有资金可提取,这将阻止合同执行转移,这将节省汽油和防止不必要的交易失败。
以下是合同的更新版本,其中包括以下改进:
contract Test {
mapping(address => uint256) public balance;
constructor() {
}
function withdraw() external {
require(balance[msg.sender] > 0, "Cannot withdraw funds: no funds available");
(bool success, ) = msg.sender.call{value: balance[msg.sender]}("");
require(success, "transfer failed");
balance[msg.sender] = 0;
}
function deposit () external payable {
balance[msg.sender] = msg.value;
}
}https://ethereum.stackexchange.com/questions/140494
复制相似问题