創宇區塊鏈:傳統安全與IPFS間的安全性研究
创宇区块链安全实验室
2022-05-25 14:03
本文约4459字,阅读全文需要约18分钟
建立在區塊鏈技術之上的Web3如何通過IPFS來保證用戶的隱私安全呢?

前言

前言

前言

知道創宇區塊鏈安全實驗室將對此進行詳細解讀。

一級標題

一級標題

一級標題

Web-interface 與IPFS

1. Web-interface 是什麼

2. IPFS 是什麼

1.永久的、去中心化保存和共享文件

星際文件系統(IPFS)是分佈式存儲和共享文件的網絡傳輸協議,它將現有的成功系統分佈式哈希表、版本控制系統Git、BitTorrent、自認證文件系統與區塊鏈相結合。正是這些系統的綜合優勢,給IPFS 帶來了以下顯著特性:

1.永久的、去中心化保存和共享文件

2.點對點超媒體:P2P 保存各種各樣類型的數據

3.版本化:可追溯文件修改歷史

4.內容可尋址:通過文件內容生成獨立哈希值來標識文件,而不是通過文件保存位置來標識https://ipfs.io當用戶將文件添加到IPFS 時,該文件會被拆分為更小的塊,經過加密哈希處理並賦予內容標識符CID 作為唯一指紋;當其他節點查找該文件時,節點會詢問對等節點誰存儲了該文件CID 引用的內容,當查看、下載這份文件時,他們將緩存一份副本——同時成為該內容的另一個提供者,直到他們的緩存被清除。

IPFS使用實例

網站

提供一個帶UI 界面的客戶端,安裝運行後會啟動IPFS 的服務,顯示當前的節點ID、網關和API 地址:

我們導入想上傳的文件,上傳文件成功後會生成該文件的CID 信息,通過QmHash(CID)我們也能查找到指定的文件:

IPFS中的傳統安全問題https://IPFS.io

根據使用實例,我們知道IPFS 允許上傳任意類型的文件,由於允許Web 訪問下載文件的特性,導致攻擊者可以像傳統安全一樣使用HTML 或SVG 文件實現釣魚:

網關為例,上傳一個Metamask 釣魚網站,由於存儲在受信域名里,受害者訪問該文件很可能攻擊成功:

`CID::=`

但由於IPFS 只能通過CID 查詢文件,使得釣魚攻擊的利用面很窄,沒辦法定向的實施攻擊。既然CID 是發起定向攻擊的關鍵,那我們回頭研究下CID。

package main

import (

"fmt"

mc "github.com/multiformats/go-multicodec"

mh "github.com/multiformats/go-multihash"

cid "github.com/ipfs/go-cid"

)

const (

File = "./go.sum"

)

func main() {

pref := cid.Prefix{

Version:  0,

Codec:    mc.Raw,

MhType:   mh.Base58,

MhLength: -1,

}

c, err := pref.Sum([]byte("CIDTest"))

if err != nil {...}

fmt.Println("CID: ", c)

}

IPLD 是構建IPFS 的數據層,它定義了默克爾鏈接(Merkle-Links)、默克爾有向無環圖(Merkle-DAG) 和默克爾路徑(Merkle-Paths)三種數據類型,通過IPLD 發送到IPFS的數據保存在鏈上,使用者會收到一個CID 來訪問該數據。

type AddEvent struct {

Name  string

Hash  string `json:",omitempty"`

Bytes int64  `json:",omitempty"`

Size  string `json:",omitempty"`

}

const (

quietOptionName       = "quiet"

quieterOptionName     = "quieter"

silentOptionName      = "silent"

progressOptionName    = "progress"

trickleOptionName     = "trickle"

wrapOptionName        = "wrap-with-directory"

onlyHashOptionName    = "only-hash"

chunkerOptionName     = "chunker"

pinOptionName         = "pin"

rawLeavesOptionName   = "raw-leaves"

noCopyOptionName      = "nocopy"

fstoreCacheOptionName = "fscache"

cidVersionOptionName  = "cid-version"

hashOptionName        = "hash"

inlineOptionName      = "inline"

inlineLimitOptionName = "inline-limit"

)

CID 是一個由Version、Codec和Multihash 三部分組成的字符串,目前分成V0和V1兩個版本。 V0 版採用Base58 編碼生成CID,V1 版包含表明內容的編號種類Codec、哈希算法MhType 和哈希長度MhLength 共同構成:

func (adder *Adder) AddAllAndPin(ctx context.Context, file files.Node) (ipld.Node, error) {

ctx, span := tracing.Span(ctx, "CoreUnix.Adder", "AddAllAndPin")

defer span.End()

我們以go-cid 生成一組CID 測試:

adder.unlocker = adder.gcLocker.PinLock(ctx)

}

defer func() {

if adder.unlocker != nil {

adder.unlocker.Unlock(ctx)

}

}()

if err := adder.addFileNode(ctx, "", file, true); err != nil {

return nil, err

}

mr, err := adder.mfsRoot()

if err != nil {

return nil, err

}

var root mfs.FSNode

可以看到在生成CID 的過程中,無法實現結果的預測和更換,我們再往上分析上傳文件的部分。將文件上傳到IPFS,通過塊的方式保存到本地blockstore 的過程位於/go-ipfs-master/core/commands/add.go:

root = rootdir

err = root.Flush()

if err != nil {

return nil, err

}

_, dir := file.(files.Directory)

var name string

if !dir {

children,把上傳文件信息保存到AddEvent 對像中,再通過/go-ipfs-master/core/coreunix/add.go 裡的addALLAndPin 和fileAdder.AddFile 方法遍歷文件路徑,讀取文件內容,將數據送入塊中:

if err != nil {

return nil, err

}

if len(children) == 0 {

return nil, fmt.Errorf("expected at least one child dir, got none")

}

name = children[0]

root, err = rootdir.Child(name)

if err != nil {

return nil, err

}

}

err = mr.Close()

if err != nil {

return nil, err

}

nd, err := root.GetNode()

if err != nil {

return nil, err

}

err = adder.outputDirs(name, root)

if err != nil {

return nil, err

}

if asyncDagService, ok := adder.dagService.(syncer); ok {

err = asyncDagService.Sync()

if err != nil {

return nil, err

}

}

if !adder.Pin {

return nd, nil

}

return nd, adder.PinRoot(ctx, nd)

}

if adder.Pin {//knownsec 如果被鎖定

func (adder *Adder) addFile(path string, file files.File) error {

var reader io.Reader = file

if adder.Progress {

rdr := &progressReader{file: reader, path: path,rootdir := mr.GetDirectory()//knownsec 獲取路徑

if fi, ok := file.(files.FileInfo); ok {

reader = &progressReader2{rdr, fi}

} else {

reader = rdr

}

}

dagnode,err := rootdir.ListNames(adder.ctx)//knownsec 展示當前路徑文件名

if err != nil {

return err

}

return adder.addNode(dagnode, path)

}

分析代碼發現,IPFS 在打包文件上傳返回CID 的整個過程,都沒實現劫持的可能,而成功上傳的文件無法實現修改其內容,同樣無法實現篡改:

後記

後記

创宇区块链安全实验室
作者文库