欧意app下载:提供新鲜的手游资讯和手游下载!

以太坊OA检查和漏洞是什么意思?

文章来源:互联网作者:欧易okex官网发布时间:2023-03-29 18:06:00

分享一个外部账户 EOA 漏洞案例。

以太坊的账户类型分为 外部账户 和 合约账户 两种类型。所谓外部账户,又称为 EOA(Externally Owned
Account),是指由用户掌握私钥的地址(用户的钱包地址一般为这种类型),而合约账户是部署到链上创建出的合约地址(多签账户的地址一般为这种类型)。

看下面的这段合约代码:

contract OnlyForEOA {

uint public flag;

// bad

modifier isNotContract(address _a){

uint len;

assembly { len :=extcodesize(_a) }

require(len==0);

_;

}

function setFlag(uint i) public isNotContract(msg.sender){

flag=i;

}

}

extcodesize 操作符返回某个地址关联的代码(code)长度,如果代码长度为0,表示为外部地址。而大于0表示为合约地址。

这段代码的本意是只允许 EOA 账户对该合约进行操作,也就是说普通用户可以直接用外部地址发起合约调用,而不允许用另一个合约进行调用。

那么上面这些代码的漏洞在哪里呢?会智能合约编程的同学可以稍微思考几分钟,再往下看。

下面的我们来部署一个攻击合约:

contract FakeEOA {

constructor(address _a) public {

OnlyForEOA c=OnlyForEOA(_a);

c.setFlag(1);

}

}

在 FakeEOA 攻击合约中,我们传入 _a 一个合约地址(准确来说是一个尚未生成的合约地址)。因为该合约地址尚未生成,当代码检查其
extcodesize 时,其结果为0。这样合约地址也被 OnlyForEOA 所接受了,这就是 OnlyForEOA 的漏洞所在。

在以太坊中,合约地址的产生是可以预先计算的。其计算逻辑为:根据发送者的地址,和交易 nonce 来确定。算法如下:

合约地址=address(uint160(uint256(keccak256(abi.encodePacked(byte(0xd6),
byte(0x94), _origin, byte(nonce))))))

讲解解决?

要解决这个问题,我们可以加上 tx.origin 的判断,如下:

require(tx.origin==msg.sender);

这样可以保证是外部账户直接调用。

另外对于 tx.origin 使用要注意相关可能的陷阱,详见之前的文章:安全|一段代码讲解偷走你的币。

欧易交易所又称欧易OKX,是世界领先的数字资产交易所,主要面向全球用户提供比特币、莱特币、以太币等数字资产的现货和衍生品交易服务,通过使用区块链技术为全球交易者提供高级金融服务。这是一款非常老牌的数字货币交易平台,平台为我们提供安全、专业的数字货币交易体验,给新手提供完整的流程引导,让你可以轻松的进行上手,同时还有客服24小时在线为你解答疑惑,为你提供最优质的的服务。