Solidity中的函数具有可见性的特性,它们指明了如何调用函数。可见性决定了一个函数是否可以由用户从外部调用(或由其他派生的合约调用),还是只能在内部或只能在外部调用。
在Solidity文档中提到四个可见性特性,默认函数是Public。不正确地使用这一函数,可能导致在智能合约中产生一些破坏性的漏洞。
坑点分析
函数的默认可见性是public。因此,不指定任何可见性的函数都可以被外部用户调用。如果开发者忽略了这一特性,本来的私有函数(或者只能在合约自身中调用)就会变成公有函数,问题也会随之而来。
我们来看一个例子。
image
代码11
在代码11这个简单的合约中,实现的是一个地址猜赏游戏。为了赢得合约的余额,用户必须生成一个以太坊地址,它最后的8个十六进制字符是0。一旦获得,他们可以调用withdrawWinnings函数来获得他们的赏金。
不幸的是,函数的可见性还没有被指定。另外,sendering ()函数是public,因此任何地址都可以调用此函数来窃取赏金。
避坑技巧
一种最好的做法是,即使合约中的所有函数都是有意公开的,也必须明确说明合约中所有函数的可见性。最近版本的Solidity将会在编译的函数没有明确的可见性设置时显示警告,以鼓励这种做法。
真实案例:Parity MultiSig Wallet的第一次黑客攻击
在第一次Parity MultiSig Wallet的事件中,大约有价值3100万美元的以太币从三个钱包中被盗了。
从本质上讲,Parity Multisig Wallet是从一个基础的Wallet合约构建的,该合约调用了一个包含核心功能的库合约。从下面的代码片段可以看出,库合约包含了钱包初始化的代码:
image
代码12
请注意,这两个函数都没有明确指定可见性,默认都是public。在钱包的构造函数中调用了initWallet()函数,并设置为multisig wallet的所有者,如 initMultiowned ()函数。
由于这些函数意外地被公开,攻击者可以通过部署的合约调用这些函数,将所有权重置为攻击者的地址。作为所有者,攻击者将所有的以太币都抽干了,价值为3100万美元。