[Celes安全局]张局谈安全 第2期
继Celes安全局第1期发布之后,小伙伴们表示意犹未尽。Celes安全局的张局长作为一名专业过(gǎo)硬(shì)的攻城狮,欢欣鼓舞为大家整理出《张局谈安全》第2期。
大家准备好,局长正式发车。
在EOS合约中总有一个apply函数,是用来将action请求映射到具体的处理函数。其实这是一个系统提供的函数,如果合约不重写自己的apply函数那么就默认使用系统的函数。如果合约需要在apply中处理自己一些特有的逻辑的时候,就需要重写apply函数,主要是过滤一些消息是否要被转发。
假下注
本合约的本意是我自己的合约和eosio.token合约的消息都要转发,其中下注的代币是eos。代码乍一看没有什么问题,其实这个apply函数存在很大的问题。那么问题在哪里呢?
我们来分析一下:
本合约转发消息的时候,只接受本合约或者eosio.token合约的action,并且使用的代币是eos。在本合约中eosio.token主要负责下注的功能,但是前面的代码只判断了转发谁的消息,并没有判断转发谁的transfer消息。这样黑客就可以以本合约的身份调用本合约的transfer,参与下注的活动,但是黑客的eos不会减少。如果黑客赢了则会获得eos奖励,如果输了则没有任何损失。
那么我们就需要增加限制条件,只有eosio.token过来的transfer消息才是正确的。这样就保证了别人不能饶过eosio.token,去调用transfer方法。
▼下面是修改后的代码
假转账
和本案例相似的还有转账假通知,其实这个也是比较简单的。
其原理是这样的,如下图所示:
在此次攻击事件中,攻击者使用账号A给自己的帐号B转账,正常的转账应该是系统合约eosio.token在收到“transfer”之后,账号A和帐号B都能收到转账通知,然而攻击者一开始便在账号B上部署了合约并增加对被攻击者合约C的转账通知“require_recipient(N(C))”,这样被攻击者也会收到A给B的转账通知。但是被攻击者的合约C并没有校验转账是否是给自己的,也就是transfer中的to是否为_self,所以被攻击者合约C收到转账消息,就傻乎乎的认为是这token是给自己的,并增加一条记录。
更通俗一点说,就好比说张三给李四转了钱,然后告诉王五:“我给李四转钱了”,王五有选择性失聪的毛病,只听到“转钱了”,然后就说:“好,我把这个帐记下来”。
其实在写合约的apply函数的时候,要特别的细心,要充分搞清楚在apply中实现的逻辑,多去设计一些测试用例,尽可能的覆盖所有case。
采取结对编程的方式,写好的代码要有人走读是最好的,这样可以有效的提高代码的安全性。
作为程序猿的我们,一定要记住“小心驶得万年船”!
▼扫码参与Celes技术交流