自己部署簽名頁
Vela 在你核准每一筆交易之前都會先解碼,這份解碼是紮實的工作——但做這份工作的,是 組出這筆交易的同一個應用程式。如果這個應用程式、或是它送到你手上的那條路被動了 手腳,它就能給你看一樣東西、卻簽下另一樣。Bybit 碰到的正是這件事。
簽名頁存在的意義,就是把這件事一分為二:交易從一個地方來,而核對和簽署發生在 另一個由你掌控的地方。
它是什麼
一個資料夾——儲存庫裡的 app-web/clearsigning——它既是一個網頁,也是一個 Chrome
擴充功能。純 HTML、CSS 和 JavaScript:沒有框架,沒有打包工具,沒有建置步驟,
沒有相依套件,也不會自己發任何網路請求。
拿到一個簽署請求時,它不相信隨請求一起送來的那份摘要。它自己解碼原始 calldata、 自己算出摘要、把這個簽章實際會授權的內容擺給你看,然後才去請求你的密碼金鑰。
因為沒有建置步驟,你讀到的檔案就是正在跑的檔案。你可以把這個資料夾跟儲存庫逐字 比對,從而確切知道自己架的是什麼。
哪一份副本才能替你的錢包簽署
密碼金鑰綁定在它被建立時的那個網域上。你的 Vela 金鑰註冊在 getvela.app 之下,
而瀏覽器只會把它們提供給一個依賴方(relying party)是 getvela.app 的頁面。
這一條規則,決定了哪一種「自己跑一份」的方式對你有用。
作為 Chrome 擴充功能——這是搭配你現有錢包該用的那一種。 不管這個資料夾從哪裡
來,擴充功能的依賴方都是 getvela.app,所以你現有的金鑰可以在裡面簽署,而跑著的
程式碼正是你載入並檢查過的那個資料夾。
- 打開
chrome://extensions,開啟開發人員模式。 - 點載入未封裝項目,選擇
app-web/clearsigning資料夾。 - 工具列上的圖示會在新分頁裡打開這個頁面。
作為你自己網域上、或是 localhost 上的一個頁面。 透過 HTTP(S) 提供服務時,
這個頁面的依賴方是它自己的主機名稱——所以它能用註冊在那個主機名稱下的金鑰簽署,
而不是註冊在 getvela.app 下的金鑰。這讓它很適合把整套流程端到端跑一遍、
跑桌面端的流程,以及替一個金鑰就建立在你自己網域下的錢包簽署。它不是一種替既有的 getvela.app 錢包簽署的方法。
cd app-web/clearsigning
python3 -m http.server 8080 # → http://localhost:8080 應用裡所有路徑都是相對的,所以放在現有主機的一個子目錄下也可以;直接從磁碟打開 index.html(file://)也能隨便看看——那種情況下沒有來源,也就沒有依賴方,
什麼都簽不了。
它在簽署之前會做什麼
- 它自己解碼這筆交易。 這個呼叫做什麼、給誰、多少錢,全部從 calldata 讀出來 ——包括批次交易裡巢狀的呼叫。
- 它只簽自己算出來的摘要。 EIP-191、EIP-712、SafeOp 和 SafeMessage 的摘要都在
頁面裡計算,並與
vela-core——錢包用的同一份程式碼——對拍。算不出的摘要就是拒簽, 而不是簽一個。 - 它檢查這筆交易就是被請求的那一筆。 網站請求的那個呼叫,必須真的在被簽的 操作裡面。
- 它拒絕無限額度的授權。 不是警告——是拒絕,並且告訴你該怎麼做。
- 它看不懂的時候會說出來, 而不是拿一段自己也擔不起責任的友善摘要頂上。
- 它顯示帳戶的位址和識別圖示, 並且不顯示由請求方提供的收款方名字。凡是請求方 能控制的東西,要麼被拿掉,要麼被明確標示成「這是它說的」。
它刻意沒有什麼
- 沒有任何編輯器。 請求一到就定死了:你要嘛簽,要嘛不簽。費用選擇器或是額度 編輯器都會重寫 calldata,而那正是這個頁面要防的病。
- 不能建立金鑰。 簽名頁沒有建立密碼金鑰的能力。建立一把新金鑰,等於建立一個 不同的帳戶。
- 不發任何網路請求。 沒有東西要抓,也就沒有東西能被攔截。
一個請求怎麼到達它
| 請求方 | 通道 |
|---|---|
| 同一個瀏覽器裡的一個頁面 | postMessage |
| 同一個瀏覽器裡的頁面,送給擴充功能 | 擴充功能連接埠 |
| 同一台機器上的桌面應用程式 | URL 片段 + 回送回呼 |
| 一支手機或是另一台電腦 | 低功耗藍牙(協定已實作;射頻部分還沒在實機上測過) |
線上格式、摘要演算法,以及一張「畫面上每一項來自哪裡」的對照表,都在程式碼旁邊的 PROTOCOL.md 裡。
什麼時候該用它
從這個帳戶開始放著你輸不起的錢那天起——而且從那之後,每一次簽署都用它。不只是 大額的時候:一筆很小的授權,就可能交出足以搬空帳戶的權限。一個只在特殊場合才拿出來 的簽署習慣,到了真正需要它的那天,其實並不在位。