首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >`msg.sender`在坚固性上优于`tx.origin`

`msg.sender`在坚固性上优于`tx.origin`
EN

Stack Overflow用户
提问于 2022-08-31 10:27:55
回答 2查看 119关注 0票数 0

我是刚接触过稳健性的人,但我多次读到应该避免使用tx.origin &应该使用msg.sender。在solidity 页面中有一个给出的演示。上面写着:-

不要使用tx.origin进行授权。假设你有这样的钱包合同:

代码语言:javascript
复制
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
// THIS CONTRACT CONTAINS A BUG - DO NOT USE
contract TxUserWallet {
    address owner;

    constructor() {
        owner = msg.sender;
    }

    function transferTo(address payable dest, uint amount) public {
        // THE BUG IS RIGHT HERE, you must use msg.sender instead of tx.origin
        require(tx.origin == owner);
        dest.transfer(amount);    // .transfer is a global variable
    }
}

现在有人骗你把以太送到这个攻击钱包的地址:

代码语言:javascript
复制
// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.7.0 <0.9.0;
interface TxUserWallet {
    function transferTo(address payable dest, uint amount) external;
}

contract TxAttackWallet {
    address payable owner;

    constructor() {
        owner = payable(msg.sender);
    }

    receive() external payable {
        TxUserWallet(msg.sender).transferTo(owner, msg.sender.balance);   //  **LINE 1**
    }
}

现在,我想知道第1行将如何从TxUserWallet中抽走全部资金。我认为transfer()是一个全局变量,它将在攻击钱包的dest中传递要处理的数量。.transfer()将如何触发合同TxAttackWalletreceive()函数。其次,在TxUserWallet(msg.sender).transferTo(owner, msg.sender.balance);行中,为什么我们要将它写成TxUserWallet(msg.sender),比如为什么我们在合同名称之后添加(msg.sender),以及通过编写msg.sender.balance传递什么值?

EN

回答 2

Stack Overflow用户

发布于 2022-08-31 13:28:52

您应该避免使用tx.origin来防止重入攻击。固体重入攻击解释

基本上,攻击者正在递归地从合同中提取资金,直到余额为0。所以有一个函数调用链。重入攻击涉及两个智能契约。易受攻击的契约和不受信任的攻击者的契约。(fallback函数是在多个条件下调用的,这使得编写每个条件的代码变得困难。这就是为什么添加receive的原因。receive被称为只有契约接收以太,因此只有在合同中没有实现函数签名时,才应该执行回退。)

msg.sender是最后一个调用者,而tx.origin是这些递归函数链的原始调用者。

funcA => funcB => funcC

msg.senderfuncC的调用者,而tx.originfuncA的调用者

现在,为了防止重入攻击,我们必须确保没有函数调用链。

代码语言:javascript
复制
require(tx.origin == msg.sender)

在你的问题中,故事有点不同。想象一下工作流。你是说

现在有人骗你把以太送到这个攻击钱包的地址:

您正在向TxAttackWallet发送资金,因此您正在启动函数链。tx.origin是你,老板,tx.origin == owner。一旦您将钱发送到TxAttackWallet,将自动调用receive of TxAttackWallet,因此这段代码将被递归执行。你在循环中

代码语言:javascript
复制
  TxUserWallet(msg.sender).transferTo(owner, msg.sender.balance);

你一直把资金从你的合同转到TxUserWallet

谁是tx.origin?这是因为您启动了这个函数链,所以这将始终通过:

代码语言:javascript
复制
 require(tx.origin == owner); 

如果您使用的是msg.sender==ownermsg.sender将是TxUserWallet,因此要求条件不会通过,也不会转移资金。

票数 2
EN

Stack Overflow用户

发布于 2022-08-31 11:26:04

.transfer()将如何触发合同TxAttackWalletreceive()功能

在不指定receive()字段的情况下,当您将ETH发送到契约地址时,会自动调用data函数。

不可能使用.transfer()函数指定数据字段,为此需要使用低级别的.call()

医生:

为什么我们把它写成TxUserWallet(msg.sender),就像为什么我们在合同名称之后添加(msg.sender),以及通过编写msg.sender.balance传递什么值一样。

TxUserWallet(msg.sender)是指向msg.sender地址(在您的例子中是TxUserWallet契约地址)的契约类型指针,期望它实现TxUserWallet的所有publicexternal函数。

这样,TxAttackWallet契约期望能够在msg.sender上调用transferTo()函数,并期望接收空响应,因为transferTo()函数不返回任何params。

msg.sender.balance返回本机余额(ETH上的ETH,Binance智能链上的BNB,.)对于msg.sender,在您的例子中,这是TxUserWallet契约地址。

医生:

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73554510

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档