智能合約里的 transferFrom 是批準轉賬流程里的關鍵函數,這個由于不如 transfer 那么常用赞厕,容易被不小心忽略艳狐。這個流程最大的問題是權限問題∶笊#看代碼說話:
// 批準轉賬上限(批準目標可以代我轉賬的上限)
function approve(address _spender, uint256 _value) public returns (bool success) {
allowed[msg.sender][_spender] = _value;
Approval(msg.sender, _spender, _value);
return true;
}
// 代我轉賬的流程
function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {
/// same as above
require(_to != 0x0);
require(balances[_from] >= _value);
require(balances[_to] + _value > balances[_to]);
uint previousBalances = balances[_from] + balances[_to];
balances[_from] -= _value;
balances[_to] += _value;
allowed[_from][msg.sender] -= _value;
Transfer(_from, _to, _value);
assert(balances[_from] + balances[_to] == previousBalances);
return true;
}
可以看出毫目,這個流程并沒做 allowed[_from][msg.sender] 和 _value 的判斷,比如函數開始應該判斷:
require(allowed[_from][msg.sender] >= _value);
如果 allowed[_from][msg.sender] 不存在诲侮,那么值是 0镀虐,判斷缺失,也就等于之前的 approve 函數形同虛設浆西。然后粉私,這還出現了個有趣的溢出:
allowed[_from][msg.sender] -= _value;
當 allowed[_from][msg.sender] 不存在,那么值是 0近零,減去 _value(大于 0 時)诺核,就溢出了(溢出并不會導致中斷回滾)。這就是為什么如果用了 SafeMath 就會沒問題久信,因為 SafeMath 會拋出錯誤窖杀,直接中斷回滾 transferFrom 函數。
整體這樣看下來裙士,EDU 和 BAI 等合約的 transferFrom 盜幣事件最核心的問題是權限問題入客,溢出在這僅僅是個小插曲而已。
本文摘自慢霧區(qū)微信公眾號文章"智能合約 transferFrom 權限控制不當導致的任意盜幣攻擊簡述"