這次我們將了解如何訪問合約中的私有數據(private 數據)。

目標合約

話不多說,直接上代碼

智能合約安全——私有數據訪問

這次我們的目標合約是部署在Ropsten 上的一個合約。

合約地址:

0x3505a02BCDFbb225988161a95528bfDb279faD6b

鏈接:

https://ropsten.etherscan.io/address/0x3505a02BCDFbb225988161a95528bfDb279faD6b#code

漏洞分析

由上面的合約代碼我們可以看到,Vault 合約將用戶的用戶名和密碼這樣的敏感數據記錄在了合約中,我們知道合約中修飾變量的關鍵字僅限制其調用範圍,這也就間接證明了合約中的數據均是公開的,可任意讀取的,將敏感數據記錄在合約中是不安全的。

讀取數據

首先,讓我們來學習一下solidity的storage存儲方式:

1)storage 中的數據被永久存儲。其以鍵值對的形式存儲在slot 插槽中。

2)storage在插槽中數據從右向左排列,空間不足時,打包當前插槽,開啟下一個插槽存儲數據;存儲定長數組(長度固定)時,數組中每一個數據佔據一個插槽。

3)存儲變長數組(長度隨元素的數量而改變)比較特殊,在遇到變長數組時,會先啟用一個新的插槽slotA 用來存儲數組的長度,其數據存儲在另外的編號為slotV 的插槽中。

slotA 表示變長數組聲明的位置,同時也存儲著變長數組的長度length:

length = sload(slotA)

用slotV表示變長數組數據存儲的位置(即key),index 表示value 對應的索引下標:

slotV = keccak256(slotA) + index

用value 表示變長數組某個數據的值:

value = sload(slotV)

下面我們就帶大家來讀取這個合約中的數據。

首先我們先看slot0 中的數據:

由合約中可以看到slot0 中只存儲了一個uint 類型的數據,我們讀取出來看一下:

我這裡使用Web3.py 取得數據,首先寫好程序

智能合約安全——私有數據訪問

運行結果:

智能合約安全——私有數據訪問

“7b”是16進制數,轉換成10進制數就是123。

這裡我們就成功的去到了合約中的第一個插槽slot0 中存儲的uint 類型的變量count=123 ,下面我們繼續:

slot1 中存儲三個變量:u16, isTrue, owner

智能合約安全——私有數據訪問

運行結果:

智能合約安全——私有數據訪問

從右往左依次為

owner = f36467c4e023c355026066b8dc51456e7b791d99

isTrue = 01 = true

u16 = 1f = 31

slot2 中就存儲著私有變量password 我們讀取看看

智能合約安全——私有數據訪問

運行結果:

智能合約安全——私有數據訪問

slot 3, 4, 5 中存儲著定長數組中的三個元素

智能合約安全——私有數據訪問

運行結果:

智能合約安全——私有數據訪問

slot6 中存儲著變長數組的長度

智能合約安全——私有數據訪問

運行結果:

智能合約安全——私有數據訪問

返回的結果顯示變長數組的長度為3。

我們從合約代碼中可以看到用戶的id 和password 是由鍵值對的形式存儲的,下面我們來讀取兩個用戶的id 和password:

user1

智能合約安全——私有數據訪問

運行結果:

智能合約安全——私有數據訪問

user2

智能合約安全——私有數據訪問

運行結果:

智能合約安全——私有數據訪問

這樣我們就成功的將合約中的所有數據讀取完成。

由此可見,合約中的私有數據也是可以讀取的

總結

大家可以看到,合約中的私有數據也是可以讀取的,所以一定不要將任何敏感數據存放在合約中哦。

如果想了解更多的智能合約和區塊鏈知識,歡迎到區塊鏈交流社區CHAINPIP社區,一起交流學習~

社區地址:https://www.chainpip.com/