您好,登錄后才能下訂單哦!
這篇文章主要介紹“Solidity合約中的整數安全問題怎么解決”,在日常操作中,相信很多人在Solidity合約中的整數安全問題怎么解決問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”Solidity合約中的整數安全問題怎么解決”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!
在傳統的桌面windows攻防對抗領域,伴隨著微軟和合作伙伴對軟件開發流程推行 SDL規范,同時對安全投入的逐步加大,單一的封包超長和文件特定字段內容超長導致的溢出漏洞在一些大型軟件里幾乎絕跡。剩余漏洞除了瀏覽器中的UAF(有隔離堆和延遲釋放對關鍵類進行利用緩解 ) ,弱類型語言存在的類型混淆,還零星剩下了一些整數類的漏洞。整數類漏洞,最近的如去年的nginx cve-2017-7529。
區塊鏈方向,比較早的整數溢出類漏洞可追溯到2010年的比特幣大整數溢出,CVE-2010-5139 ,黑客通過整數溢出構造了大概 92233720368.54277039 個比特幣,最近的SMT/BEC的整數安全場景與之前比特幣的場景類似。
傳統安全領域中,整數安全與數據模型和整數運算支持的運算符相關,其中數據模型又跟處理器架構體系和操作系統平臺相關。如圖1。
圖1
C中容易引發整數安全問題的運算符簡要羅列如下,如圖2。
圖2
Solidity合約中的整數安全場景與之類似。
SMT 和 BEC 都是以太坊代幣生態下的一個普通的 ERC-20 代幣。轉賬流通都是通過以太坊的solidity合約進行實現。
區塊鏈1.0的比特幣也有腳本語言,但是為了安全閹割掉了循環和遞歸等圖靈完備性語言才有的功能。以太坊 Solidity設計之初就被定位為圖靈完備性語言。 Solidity的圖靈完備性也為后續的合約漏洞陸續埋下了伏筆,如 The Dao 漏洞事件直接導致以太坊硬分叉成了eth 和舊鏈etc。
Solidity語言暫不支持類似于C中的 float double 等浮點型數據類型。支持int/uint變長的有符號或無符號整型。變量支持的步長以8 遞增,支持從uint8
到uint256
,以及int8
到int256
。需要注意的是,uint
和int
默認代表的是uint256
和int256
。uint8
的數值范圍與 C中的uchar相同,即取值范圍是0 到 2^8-1,uint256支持的取值范圍是 0 到 2^256-1,余下數據類型以此類推。
Solidity語言中對于運算符的支持如下。
比較:
<=
,<
,==
,!=
,>=
,>
,返回值為bool
類型。位運算符:
&
,|
,(^
異或),(~
非)。數學運算:
+
,-
,一元運算+
,*
,/
,(%
求余),(**
平方)。
Solidity合約代碼的邏輯都相對簡單,運算符的使用中加法 減法和乘法居多。
以太坊提供有一個Solidity語言的在線編譯測試工具。http://remix.ethereum.org/#optimize=false&version=soljson-v0.4.23+commit.124ca40d.js 我們以加法和減法運算作為舉例,簡單說明下整數溢出在Solidity 語言中的常規情況。
編寫如下solidity測試代碼。
pragma solidity ^0.4.0;
contract C {
// (2**256 - 1) + 1 = 0
function overflow() returns (uint256 _overflow) {
uint256 max = 2**256 - 1;
return max + 1;
}
// 0 - 1 = 2**256 - 1
function underflow() returns (uint256 _underflow) {
uint256 min = 0;
return min - 1;
}
}
在線測試工具中編譯運行結果如下如圖3圖4。
圖3
圖4
可以看到uint256當取最大整數值,上溢之后直接回繞返回值為0 , uint256當取0下溢之后直接回繞,返回值為 2^256-1 。這是 solidity中整數溢出場景的常規情況。
為了減少solidity合約開發中產生的安全問題,以太坊的官方開發博客陸續發布了一些與 solidity開發安全相關的博文。在 2017年 8月 6日 單獨發過一篇使用SafeMath 庫進行整數安全操作的文章<< SafeMath to protectfrom overflows >> 。詳見鏈接: https://ethereumdev.io/safemath-protect-overflows/
/**
* @title SafeMath
* @dev Math operations with safety checks that throw on error
*/
library SafeMath {
function mul(uint256 a, uint256 b) internal constant returns (uint256) {
uint256 c = a * b;
assert(a == 0 || c / a == b);
return c;
}
function div(uint256 a, uint256 b) internal constant returns (uint256) {
// assert(b > 0); // Solidity automatically throws when dividing by 0
uint256 c = a / b;
// assert(a == b * c + a % b); // There is no case in which this doesn't hold
return c;
}
function sub(uint256 a, uint256 b) internal constant returns (uint256) {
assert(b <= a);
return a - b;
}
function add(uint256 a, uint256 b) internal constant returns (uint256) {
uint256 c = a + b;
assert(c >= a);
return c;
}
}
可以看到相關的可能產生溢出的操作都單獨封裝成函數,加入assert 斷言做判斷避免溢出。調用 SafeMath庫的方法如圖 5。
圖5
與大型軟件或者操作系統動輒十萬行甚至千萬行代碼不同,智能合約的代碼行數通常不多,功能也不是很復雜。一起來看下SMT 合約的相關代碼。
SMT的合約地址是 https://etherscan.io/address/0x55f93985431fc9304077687a35a1ba103dc1e081#code
問題存在于transferProxy()函數 代碼如下,如圖6
圖6
在進行加法操作的時候沒有采用Safemath庫進行約束。 _feeSmt參數和 _value參數均可以被外界進行控制, _feeSmt和 value均是 uint256 無符號整數,相加后最高位舍掉,結果為0。如圖7
圖7
直接溢出繞過代碼檢查導致可以構造巨大數量的smt代幣并進行轉賬。如圖8
圖8
攻擊者的惡意轉賬記錄可以從如下鏈接進行看到:
https://etherscan.io/tx/0x1abab4c8db9a30e703114528e31dee129a3a758f7f8abc3b6494aad3d304e43f
如圖9
圖9
BEC的合約地址是0xC5d105E63711398aF9bbff092d4B6769C82F793D ,合約代碼可以訪問 etherscan的如下網址進行查看https://etherscan.io/address/0xc5d105e63711398af9bbff092d4b6769c82f793d#code 。代碼一共是299行。
問題函數如圖10。
圖10
可以看到batchTransfer函數中 ,語句 balances[msg.sender] = balances[msg.sender].sub(amount)和 balances[_receivers[i]] = balances[_receivers[i]].add(_value) 中,調用 Safemath庫中的安全函數來完成加減操作,但是在第三行代碼, uint256 amount = uint256(cnt) * _value 卻直接使用乘法運算符。
其中變量cnt為轉賬的地址數量,可以通過外界的用戶輸入 _receivers進行控制, _value為單地址轉賬數額,也可以直接進行控制。乘法運算溢出,產生了非預期 amount 數值,并且外界可以通過調整_receivers 和_value 的數值進行操控。緊接著下面有一句對 amount進行條件檢查的代碼 require(_value > 0&& balances[msg.sender] >= amount); 其中 balances[msg.sender]代表當前用戶的余額。amount代表要轉的總幣數。代碼意思為確保 當前用戶擁有的代幣余額大于等于轉賬的總幣數才進行后續轉賬操作。因為通過調大單地址轉賬數額 _value的數值,amount 溢出后可以為一個很小的數字或者0 ,很容易繞過balances[msg.sender] >= amount 的檢查代碼。從而產生巨大_value數額的惡意轉賬。
攻擊者的惡意轉賬記錄,可以從如下鏈接看到https://etherscan.io/tx/0xad89ff16fd1ebe3a0a7cf4ed282302c06626c1af33221ebe0d3a470aba4a660f 。如圖11
圖11
可以從代碼totalSupply進行看到,bec 代幣總量共計才 7 000 000 000枚。 如圖12
圖12
但是攻擊者通過溢出amount繞過后續 require中的判定條件分別向兩個地址惡意轉賬了 57,896,044,618,658,100,000,000,000,000,000,000,000,000,000,000,000,000,000,000.792003956564819968 枚bec 代幣。
到此,關于“Solidity合約中的整數安全問題怎么解決”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。