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