据悉,Solidity 0.4.22版本在更新后,引入一种新的构造函数声明形式:constructor()public {},通过这种写法,可以避免在合约开发过程中误将构造函数名写错,使得其变为普通函数。任何人在合约开发过程中,均可以调用这个函数。
但经链安科技自主研发的VaaS平台分析区块链智能合约时发现,有开发者对constructor函数的使用存在问题。即,新的构造函数在给合约开发者带来便利的同时,如果合约开发者使用不当会存在一定的隐患,严重时甚至会给项目方及Token持有者带来利益上的损害。
据链安创始人杨霞分析,owned合约的constructor()函数,即构造函数,将合约创建者地址赋予owner,用于后续的身份验证。但是合约的构造函数声明存在错误,将constructor() 误写成了 functionconstructor(),进而产生了安全问题。
注:msg.sender 为当前操作账户地址、owner为合约管理者地址
由于 functionconstructor()不是构造函数的声明形式,这里相当于声明了一个函数名为constructor的普通函数,可被执行多次;而constructor函数的可见性修饰符为public,可被其他账户地址调用并修改owner的值,盗用合约管理权限。
以下通过Ropsten测试链对该问题进行验证:
使用remix编译部署测试合约Test,地址为:
0x9e238a179b712D7d35F86137c49053Cc4f513a41,
合约代码如下:
pragma solidity ^0.4.22;
contract Test {
address public owner;
function constructor() public {
owner = msg.sender;
}
}
可以看到,刚部署合约后合约的owner为0地址,因为并没有构造函数对其进行赋值。
现在使用Remix调用constructor函数,发现交易失败,分析后发现data字段不是constructor的函数签名(0x3078756e646566696e6564)。
更换另一个版本的solidity编译器http://dapps.oraclize.it/browser-solidity。
执行constructor函数,发现owner被更改,说明该漏洞存在:
经对该漏洞进行分析,其可能导致的后果如下:
如何避免?
既然合约开发者可能会存在使用constructor函数不当,那么作为项目方应该如何去防范后期可能造成的风险呢?在此,安全公司链安给出的建议方法为如下两种:
1.新的constructor使用方法为,前面无function声明:
contract TokenExample {
constructor() public {
//...
}
}
2.Remix-ide等编译器会对constructor的错误使用产生警告,开发者千万不要忽略编译器告警,推荐更改源码,消除所有编译器警告。
再次提醒项目方,开发者书写合约敏感函数(如构造函数、回调函数)时,应严格遵循官方命名要求,并重视编译器提出的警告。同时,合约在发布到主链前,开发者应在官方提供的测试网络上进行充分验证,从多角度分析合约代码,找出那些容易忽略的问题,并且做到防患于未然。
杨霞 成都链安科技CEO,创始人。电子科技大学副教授,最早研究区块链形式化验证的专家。一直为航空航天、军事领域提供形式化验证服务。主持国家核高基、装发重大软件课题等近10项国家课题。CC国际安全标准成员、CCF区块链专委会委员。发表学术论文30多篇,申请20多项专利。
最新热文: