淺談以太坊元交易的新型授權釣魚風險
一、什么是元交易
設想這樣一個場景:你被DeFi的高收益所吸引,所以決定將交易所里的USDC全部提到錢包,然后投入到DeFi中,在提現完成后,你錢包確實收到了USDC,但你發(fā)現你不能完成任何鏈上操作,不能交易,不能質押。所以,你又需要重新從交易所中購買一些ETH再提到錢包....
在常規(guī)情況下,用戶想要在區(qū)塊鏈上發(fā)布一筆交易,需要賬戶內有足夠的的原生代幣(native coin,ETH、BTC這類)作為交易手續(xù)費,然后才能上鏈。而在使用元交易的情況下,用戶可以不用自己發(fā)布交易,轉而委托中繼者(relay)代為發(fā)布,這樣自然也就不需要用戶自己有足夠的的原生代幣。
要實現交易委托,需要目標智能合約支持元交易,實現的方式一般是使用消息簽名技術,使用錢包進行簽名是不需要任何手續(xù)費的,因為這完全是鏈下行為,用戶構造相應的元交易數據,并簽名,然后將這些信息發(fā)送給中繼者,接著中繼者再對目標合約進行調用,并附帶數據與簽名,目標合約收到這些信息后進行驗證后再執(zhí)行相應的業(yè)務。
有一點要搞明白,元交易雖然是GasLess(免gas)的,但并不代表無需手續(xù)費,是否需要付出手續(xù)費,以及付出何種資產作為手續(xù)費,主要取決于中繼者,一般來說,可以用主流token支付,所以你需要再簽署一筆向中繼者支付手續(xù)費的元交易。
總而言之,元交易的本質是一組信息憑證,是用戶期望行為的一種證明,且具有真實的可執(zhí)行力,第三方可以拿這些信息替用戶執(zhí)行想要執(zhí)行的動作。
二、ERC20-permit(EIP-2612)
場景繼續(xù):當你準備購買ETH作為手續(xù)費時,你突然發(fā)現,USDC居然支持元交易,只需要簽署一則消息即可完成授權,簡直不要太方便!
ERC20是在以太坊上面創(chuàng)建token的實現標準,但是它并不支持元交易,如果token需要支持授權元交易,則需要按照EIP-2612的規(guī)范來進行擴展,如下:
新增了3個函數:
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external
function nonces(address owner) external view returns (uint)
function DOMAIN_SEPARATOR() external view returns (bytes32)
- permit函數:一般由中繼者調用,負責驗證參數與簽名是否相符,然后進行授權(approve)操作
- nonces函數:返回指定用戶的nonce,在每次permit之后,nonce遞增,為了防止一筆元交易被重復執(zhí)行
- DOMAIN_SEPARATOR函數:根據chainId、合約地址等信息生成一個唯一散列,防止一筆元交易在其他EVM鏈(ETC、BSC等)上被重放
最重要的是permit函數,所以看一下這個函數的具體實現,這里參考uniswap:
https://github.com/Uniswap/v2-core/blob/master/contracts/UniswapV2ERC20.sol
function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external {
require(deadline >= block.timestamp, 'UniswapV2: EXPIRED');
bytes32 digest = keccak256(
abi.encodePacked(
'\x19\x01',
DOMAIN_SEPARATOR,
keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
)
);
address recoveredAddress = ecrecover(digest, v, r, s);
require(recoveredAddress != address(0) && recoveredAddress == owner, 'UniswapV2: INVALID_SIGNATURE');
_approve(owner, spender, value);
}
很短幾行代碼,可以看到,在進行了驗簽以及其他檢測后,會執(zhí)行授權操作,所以整個流程其實很簡單,用戶完成鏈下簽名,中繼進行鏈上調用,僅此而已。
三、 隱患
場景最后:錢包彈出了”請求簽名“,上面的信息你有些看不懂,但是錢包并沒有任何警告信息,也不用花錢,你很輕易的完成了確認,兩分鐘后,你錢包里的USDC全都消失了...
毫無疑問,與approve授權釣魚類似,元交易也是存在釣魚風險的,只要竊取到了簽名,就竊取到了授權,更加危險,更容易中招,相對來說,元交易釣魚目前存在以下”優(yōu)勢“
1、主流幣種支持
雖然元交易尚未普及,但也有不少主流幣種支持了ERC20-permit:
- USDC
- DAI
- UNI
- 1INCH
- ENS
2、警告信息缺失
相對于approve授權釣魚,錢包對于元交易授權的警告幾乎沒有,以下測試了最新版本的主流錢包告警情況
MetaMask,無特別提醒
TokenPocket,無特別提醒,簽名內容未處理
imtoken,無特別提醒
3、隱蔽性強
傳統(tǒng)的授權釣魚會在鏈上留下approve記錄,而元交易釣魚完全是鏈下行為,卻又能夠影響鏈上,對于元交易簽名已泄露的用戶來說,是一個定時炸彈,而且還不自知。
4、成本低廉
對于需要上鏈的操作,由于操作成本等原因,用戶會相對謹慎,但對于鏈下簽名,就會放松很多了,且無需成本,用戶也很難會意識到簽名操作也會影響到資產安全。
5、難以理解
除了基于EIP-2612實現的ERC20授權元交易外,還有很多項目方自己設計的元交易實現,而這些實現是非標準的,所以也無法被錢包所理解,并形成相應的警告,用戶也很難理解其中含義。