可信簽署器
Vela 在你核准每一筆交易之前都會先解碼,而這份解碼是實實在在的工作——但做這件事的,是組出這筆交易的同一個應用程式。如果這個應用程式、或它送到你手上的那條路被動了手腳,它就能給你看一樣東西、卻簽下另一樣。Bybit 遇到的正是這件事。
可信簽署器存在的意義,就是把這件事一分為二:應用程式只負責把請求交出去,核對和簽署則在另一個頁面上進行——一個你可以從頭讀到尾、逐位元組重新建置,或自己執行的頁面。
它在哪裡執行
官方頁面由 sign.getvela.app 提供。桌面版(macOS、Windows、Linux)、iPhone 和 Android 應用程式都能把請求送給它:應用程式會在瀏覽器分頁裡開啟這個頁面,請求就放在連結裡;你在那裡核對,並用密碼金鑰簽署,頁面再透過一個 velawallet:// 連結把簽章交回應用程式。網頁版錢包無法使用它。
它需要你主動選用。你在建立錢包或登入時把它選為簽署方式,從那之後,這個錢包在那台裝置上的每一次簽署都會經過它。它也能建立錢包的金鑰。在 sign.getvela.app 上,它用的是和各個應用程式相同的 getvela.app 密碼金鑰。
它在簽署之前會做什麼
- 它自己解碼請求。 這個呼叫在做什麼、給誰、多少錢,全都從 calldata 讀出來——包括批次交易裡巢狀的呼叫。
- 它只簽自己算出來的摘要值。 EIP-191、EIP-712、SafeOp 和 SafeMessage 的摘要值都在頁面裡計算,從不採用請求端提供的;測試會把 SafeOp 和 SafeMessage 的摘要值拿去和
vela-core——錢包使用的程式碼——交叉比對,而應用程式只接受針對它自己算出的那個摘要值的簽章,其他摘要值上的簽章一律拒收。 - 它會檢查這筆交易就是被請求的那一筆。 網站請求的那個呼叫,必須真的在被簽署的操作裡面,否則頁面會拒絕簽署。
- 它會指出無上限的授權。 它改不了金額——不是簽收到的那些位元組,就是什麼都不簽——所以無上限的授權或 permit(2^200 以上,Permit2 為 2^152 以上,與 App 同一條線)會以紅色顯示並註明這個原因,可以照原樣簽署;鏈上授權的上限,要在請求送到這裡之前,就在錢包自己的授權畫面上選好。針對整個 NFT 系列的授權會被拒絕。
- 它會拒絕自己無法擔保的東西:
eth_sign、它不認得的方法、轉給該代幣本身合約的代幣、它讀不懂的操作,以及挑戰值由請求端提供的登入。 - 它會拒絕會交出你帳戶的請求,規則與 App 相同:帳戶對自己的擁有者、模組、guard 或 fallback 函式發起呼叫(放進批次交易裡也一樣);
delegatecall,除非目標是 Safe 的 MultiSend 合約(它把一個操作裡的各個呼叫打包在一起);以及SafeTx簽署。它檢查的是 App 組裝的操作裡的每一個呼叫,而不只是網站請求的那幾個。 - 它會顯示帳戶的位址,以及在頁面上算出的識別圖示。 收款人和合約的名稱從不取自請求——只有頁面自己那份經過審閱的表格才能替合約命名。帳戶自己的名稱(由應用程式送來,好讓你挑對密碼金鑰)會顯示在它的位址旁邊。
- 每一次簽署都會要求使用者驗證(你的指紋、臉部或 PIN 碼)。
它刻意不具備的功能
- 沒有任何編輯器。 請求一送到就固定了:你要嘛簽,要嘛不簽。手續費選擇器或額度編輯器都會改寫 calldata,而那正是這個頁面要防的毛病。
- 不存取網路。 這個頁面是一個檔案,它的內容安全政策(
default-src 'none')就寫在它自己的位元組裡,所以它無法取得任何東西、無法建立連線,也無法載入圖片。唯一會離開它的是它的回覆——它會依照請求裡的回呼連結送出(由 Vela 應用程式發起時是velawallet://)。代幣圖示是用字母畫出來的。
應用程式反過來會核對什麼
應用程式也不信任這個頁面。只有在下列條件全部成立時,它才會接受一個簽章:被簽署的挑戰值就是應用程式自己算出的摘要值、做過使用者驗證、金鑰是你錢包的金鑰之一,而且這個 P-256 簽章能用那把金鑰驗證通過。
每一個已發布的版本,都能核對
每個版本都從 app-web/trusted-signer/src/ 建置成單一檔案,而且可重現——Bun 和 Node 產出的位元組完全相同——並發布在它自己的位址 sign.getvela.app/b/<sha256>/sign.html,和先前的每一個版本並列。版本清單在 sign.getvela.app/index.json。
cd app-web/trusted-signer
node samples/build-single.mjs --check # rebuilds a version listed in dist/
curl -sL https://sign.getvela.app/b/<sha256>/sign.html | shasum -a 256 桌面版啟動時,會取得它即將開啟的那個已發布版本、計算雜湊值,再和內建的版本比對。比對結果只會寫進紀錄檔,不相符的頁面照樣會開啟。手機版還不做這項檢查。
執行你自己的副本
設定裡保存著各個應用程式開啟的那個頁面的位址,所以你可以把它指向你自己的部署:任何 HTTPS 位址,或測試用的 localhost。用 bun samples/build-single.mjs(或 node)建置,再把 dist/ 複製到你的主機上。
放在你自己網域上的副本,會用為那個網域建立的密碼金鑰簽署,而不是 getvela.app 的密碼金鑰——所以它是一種建立並使用「金鑰屬於你網域」的錢包的方式,而不是替已經存在的 getvela.app 錢包簽署的方式。一個錢包的所有金鑰都屬於同一個網域。
程式碼,以及建置和檢查它的指令碼,都在 app-web/trusted-signer/ 裡。