當(dāng)前位置:首頁 > 物聯(lián)網(wǎng) > 區(qū)塊鏈
[導(dǎo)讀] 本次教程主要展示在編寫智能合約時通常應(yīng)遵循的安全模式。 方案建議 以下建議適用于以太坊上任何智能合約系統(tǒng)的開發(fā)。 外部調(diào)用 使用外部調(diào)用時需要格外注意 調(diào)

本次教程主要展示在編寫智能合約時通常應(yīng)遵循的安全模式。

方案建議

以下建議適用于以太坊上任何智能合約系統(tǒng)的開發(fā)。

外部調(diào)用

使用外部調(diào)用時需要格外注意

調(diào)用不受信任的智能合約可能會帶來一些意外的風(fēng)險或Bug。外部調(diào)用可能在該合約或它依賴的任何其他合約中執(zhí)行惡意代碼。因此,每個外部調(diào)用都應(yīng)視為潛在的安全風(fēng)險。 如果無法或不希望刪除外部調(diào)用,請使用本節(jié)教程的建議將危險降至最低。

標(biāo)記不受信任的合約

當(dāng)與外部合約進(jìn)行交互時,請以清楚表明與它們進(jìn)行交互不安全的方式命名變量,方法和合約接口,適用于您自己的調(diào)用外部合約的函數(shù)。

// bad

Bank.withdraw(100); // Unclear whether trusted or untrusted

function makeWithdrawal(uint amount) { // Isn‘t clear that this funcTIon is potenTIally unsafe

Bank.withdraw(amount);

}

// good

UntrustedBank.withdraw(100); // untrusted external call

TrustedBank.withdraw(100); // external but trusted bank contract maintained by XYZ Corp

funcTIon makeUntrustedWithdrawal(uint amount) {

UntrustedBank.withdraw(amount);

}

避免外部調(diào)用后的狀態(tài)更改

無論使用原始調(diào)用(形式為someAddress.call())還是合約調(diào)用(形式為ExternalContract.someMethod()),都可能存在執(zhí)行惡意代碼的風(fēng)險。 即使ExternalContract不是惡意的,惡意代碼也可以通過其調(diào)用的任何合約執(zhí)行。

一種特別的危險是惡意代碼可能會劫持控制流,從而導(dǎo)致由于可重入而產(chǎn)生的漏洞。

如果要調(diào)用不受信任的外部合約,請避免在調(diào)用后更改狀態(tài)。這種模式有時也被稱為檢查效果交互模式。

避免使用transfer()和send()

.transfer()和.send()都會將2300gas轉(zhuǎn)發(fā)給收件人。這一硬編碼gas津貼的目的是防止重入漏洞,但這只有在gas成本不變的假設(shè)下才有意義。最近的EIP 1283(在最后一刻退出了君士坦丁堡硬叉)和EIP 1884(預(yù)計將在伊斯坦布爾硬叉中到達(dá))表明此假設(shè)無效。

為了避免將來gas成本發(fā)生變化時會產(chǎn)生問題,最好改用.call.value(amount)(“”)。請注意,這無助于減輕重入攻擊,因此必須采取其他預(yù)防措施。

處理外部調(diào)用中的Bug

Solidity提供了適用于原始地址的低級調(diào)用方法:address.call(),address.callcode(),address.delegatecall()和address.send()。 這些低級方法從不拋出異常,但是如果調(diào)用遇到異常,則將返回false。 另一方面,合同調(diào)用(例如,ExternalContract.doSomething())將自動傳播一個引發(fā)(例如,如果doSomething()引發(fā),則ExternalContract.doSomething()也將引發(fā))。

如果選擇使用低級調(diào)用方法,請確保通過檢查返回值來處理調(diào)用失敗的可能性。

// bad

someAddress.send(55);

someAddress.call.value(55)(“”); // this is doubly dangerous, as it will forward all remaining gas and doesn’t check for result

someAddress.call.value(100)(bytes4(sha3(“deposit()”))); // if deposit throws an excepTIon, the raw call() will only return false and transaction will NOT be reverted

// good

(bool success, ) = someAddress.call.value(55)(“”);

if(!success) {

// handle failure code

}

ExternalContract(someAddress).deposit.value(100)();

支持外部調(diào)用push

外部調(diào)用可能發(fā)生意外或者惡意BUG。為了最大限度地減少此類故障造成的損害,通常最好將每個外部調(diào)用隔離到自己的事務(wù)中,該事務(wù)可以由調(diào)用的接收者發(fā)起。這與支付尤其相關(guān),在支付中,最好讓用戶提取資金,而不是自動向他們推送資金。(這也降低了GAS限制出現(xiàn)問題的可能性)避免在一個事務(wù)中合并多個以太坊轉(zhuǎn)移。

// bad

contract auction {

address highestBidder;

uint highestBid;

function bid() payable {

require(msg.value 》= highestBid);

if (highestBidder != address(0)) {

(bool success, ) = highestBidder.call.value(highestBid)(“”);

require(success); // if this call consistently fails, no one else can bid

}

highestBidder = msg.sender;

highestBid = msg.value;

}

}

// good

contract auction {

address highestBidder;

uint highestBid;

mapping(address =》 uint) refunds;

function bid() payable external {

require(msg.value 》= highestBid);

if (highestBidder != address(0)) {

refunds[highestBidder] += highestBid; // record the refund that this user can claim

}

highestBidder = msg.sender;

highestBid = msg.value;

}

function withdrawRefund() external {

uint refund = refunds[msg.sender];

refunds[msg.sender] = 0;

(bool success, ) = msg.sender.call.value(refund)(“”);

require(success);

}

}

不要將調(diào)用委托給不受信任的代碼

delegateCall函數(shù)用于從其他合約調(diào)用函數(shù),就好像它們屬于調(diào)用方合約一樣。因此調(diào)用方可以改變調(diào)用地址的狀態(tài),這是存在風(fēng)險。下面的示例演示了使用delegatecall如何導(dǎo)致合約的破壞和資金損失。

contract Destructor

{

function doWork() external

{

selfdestruct(0);

}

}

contract Worker

{

function doWork(address _internalWorker) public

{

// unsafe

_internalWorker.delegatecall(bytes4(keccak256(“doWork()”)));

}

}

如果使用已部署的Destructor合約的地址作為參數(shù)調(diào)用Worker.doWork(),則Worker合約將自毀。 僅將執(zhí)行委托給受信任的合約,而不委托給用戶提供的地址。

不要假設(shè)合約是用零余額創(chuàng)建的,攻擊者可以在創(chuàng)建合約之前將以太坊發(fā)送到該合約的地址。

請記住,可以強(qiáng)制將以太坊發(fā)送到一個帳戶

小心編寫嚴(yán)格檢查智能合約的余額的不變量。

攻擊者可以強(qiáng)行將以太坊發(fā)送到任何帳戶,并且這是無法避免的(即使使用執(zhí)行revert()的回退函數(shù)也無法阻止)。

攻擊者可以通過創(chuàng)建合約,用1 wei資助該合約并調(diào)用selfdestruct(victimAddress)來實現(xiàn)此目的。在victimaddress中沒有調(diào)用任何代碼,因此無法阻止它。發(fā)送到礦工的地址的區(qū)塊獎勵也是如此,該地址可以是任意地址。

此外,由于可以預(yù)先計算合約地址,因此可以在部署合約之前將以太坊發(fā)送到某個地址。

請記住,鏈上數(shù)據(jù)是公開的

許多應(yīng)用程序要求提交的數(shù)據(jù)在某個時間點之前都是隱匿的。游戲(如鏈上剪刀石頭布)和拍賣機(jī)制(如競價拍賣)兩大類例子。如果您在構(gòu)建隱私問題的應(yīng)用程序,請確保避免用戶過早公布信息。最好的策略是使用具有不同階段的承諾方案:首先使用值的哈希值進(jìn)行提交,然后在后續(xù)階段中顯示值。

例子:

在剪刀石頭布上,要求兩個玩家先提交其預(yù)期動作的哈希值,然后要求兩個玩家均提交其動作;如果提交的動作與散列不匹配,則將其丟棄。

在拍賣中,要求玩家在初始階段提交其出價值的哈希值(以及大于其出價值的保證金),然后在第二階段提交其拍賣出價。

開發(fā)依賴于隨機(jī)數(shù)生成器的應(yīng)用程序時,順序應(yīng)始終為(1)玩家提交動作,(2)生成隨機(jī)數(shù),(3)玩家支付。產(chǎn)生隨機(jī)數(shù)的方法本身就是積極研究的領(lǐng)域。當(dāng)前同類最佳的解決方案包括比特幣區(qū)塊頭(通過http://btcrelay.org驗證),哈希提交顯示方案(即,一方生成數(shù)字,發(fā)布其哈希值以“提交”給該值,以及然后顯示價值)和RANDAO。由于以太坊是確定性協(xié)議,因此協(xié)議中的任何變量都不能用作不可預(yù)測的隨機(jī)數(shù)。還應(yīng)注意,礦工在某種程度上控制著block.blockhash()值*。

注意某些參與者可能“下線”而不上線的可能性

不要依賴于由特定方執(zhí)行特定操作的退款或索賠程序,而沒有其他方法將資金取出。例如在石頭剪刀布游戲中,一個常見的錯誤是在兩個玩家都提交動作之前不進(jìn)行支付。 但是惡意的玩者可以通過根本不提交自己的舉動來“困擾”對方-實際上,如果一個玩者看到了對方顯示的舉動并確定自己輸了,則根本沒有理由提出自己的舉動。

(1)提供一種規(guī)避未參與參與者的方法,可能會在一定時限內(nèi)進(jìn)行;

(2)考慮為參與者在其所處的所有情況下提交信息提供額外的經(jīng)濟(jì)激勵。

注意負(fù)整數(shù)取反

solidity提供了幾種處理有符號整數(shù)的類型。與大多數(shù)編程語言一樣,在solidity中,帶n位的有符號整數(shù)可以表示從-2^(n-1)到2^(n-1)-1的值。這意味著MIN_INT沒有正等價物。求反是通過找到一個數(shù)字的兩個補數(shù)實現(xiàn)的,因此,最負(fù)數(shù)的求反將得出相同的值。

contract Negation {

function negate8(int8 _i) public pure returns(int8) {

return -_i;

}

function negate16(int16 _i) public pure returns(int16) {

return -_i;

}

int8 public a = negate8(-128); // -128

int16 public b = negate16(-128); // 128

int16 public c = negate16(-32768); // -32768

}

處理此問題的一種方法是,在求反之前檢查變量的值,如果該值等于最小整數(shù),則拋出。另一種選擇是確保使用容量更大的類型(例如int32而不是int16)永遠(yuǎn)不會達(dá)到最大負(fù)數(shù)。

當(dāng)min_int乘以或除以-1時,int類型也會出現(xiàn)類似的問題。

來源: 區(qū)塊鏈研究實驗室

本站聲明: 本文章由作者或相關(guān)機(jī)構(gòu)授權(quán)發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內(nèi)容真實性等。需要轉(zhuǎn)載請聯(lián)系該專欄作者,如若文章內(nèi)容侵犯您的權(quán)益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

9月2日消息,不造車的華為或?qū)⒋呱龈蟮莫毥谦F公司,隨著阿維塔和賽力斯的入局,華為引望愈發(fā)顯得引人矚目。

關(guān)鍵字: 阿維塔 塞力斯 華為

加利福尼亞州圣克拉拉縣2024年8月30日 /美通社/ -- 數(shù)字化轉(zhuǎn)型技術(shù)解決方案公司Trianz今天宣布,該公司與Amazon Web Services (AWS)簽訂了...

關(guān)鍵字: AWS AN BSP 數(shù)字化

倫敦2024年8月29日 /美通社/ -- 英國汽車技術(shù)公司SODA.Auto推出其旗艦產(chǎn)品SODA V,這是全球首款涵蓋汽車工程師從創(chuàng)意到認(rèn)證的所有需求的工具,可用于創(chuàng)建軟件定義汽車。 SODA V工具的開發(fā)耗時1.5...

關(guān)鍵字: 汽車 人工智能 智能驅(qū)動 BSP

北京2024年8月28日 /美通社/ -- 越來越多用戶希望企業(yè)業(yè)務(wù)能7×24不間斷運行,同時企業(yè)卻面臨越來越多業(yè)務(wù)中斷的風(fēng)險,如企業(yè)系統(tǒng)復(fù)雜性的增加,頻繁的功能更新和發(fā)布等。如何確保業(yè)務(wù)連續(xù)性,提升韌性,成...

關(guān)鍵字: 亞馬遜 解密 控制平面 BSP

8月30日消息,據(jù)媒體報道,騰訊和網(wǎng)易近期正在縮減他們對日本游戲市場的投資。

關(guān)鍵字: 騰訊 編碼器 CPU

8月28日消息,今天上午,2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會開幕式在貴陽舉行,華為董事、質(zhì)量流程IT總裁陶景文發(fā)表了演講。

關(guān)鍵字: 華為 12nm EDA 半導(dǎo)體

8月28日消息,在2024中國國際大數(shù)據(jù)產(chǎn)業(yè)博覽會上,華為常務(wù)董事、華為云CEO張平安發(fā)表演講稱,數(shù)字世界的話語權(quán)最終是由生態(tài)的繁榮決定的。

關(guān)鍵字: 華為 12nm 手機(jī) 衛(wèi)星通信

要點: 有效應(yīng)對環(huán)境變化,經(jīng)營業(yè)績穩(wěn)中有升 落實提質(zhì)增效舉措,毛利潤率延續(xù)升勢 戰(zhàn)略布局成效顯著,戰(zhàn)新業(yè)務(wù)引領(lǐng)增長 以科技創(chuàng)新為引領(lǐng),提升企業(yè)核心競爭力 堅持高質(zhì)量發(fā)展策略,塑強(qiáng)核心競爭優(yōu)勢...

關(guān)鍵字: 通信 BSP 電信運營商 數(shù)字經(jīng)濟(jì)

北京2024年8月27日 /美通社/ -- 8月21日,由中央廣播電視總臺與中國電影電視技術(shù)學(xué)會聯(lián)合牽頭組建的NVI技術(shù)創(chuàng)新聯(lián)盟在BIRTV2024超高清全產(chǎn)業(yè)鏈發(fā)展研討會上宣布正式成立。 活動現(xiàn)場 NVI技術(shù)創(chuàng)新聯(lián)...

關(guān)鍵字: VI 傳輸協(xié)議 音頻 BSP

北京2024年8月27日 /美通社/ -- 在8月23日舉辦的2024年長三角生態(tài)綠色一體化發(fā)展示范區(qū)聯(lián)合招商會上,軟通動力信息技術(shù)(集團(tuán))股份有限公司(以下簡稱"軟通動力")與長三角投資(上海)有限...

關(guān)鍵字: BSP 信息技術(shù)
關(guān)閉
關(guān)閉