在去中心化金融(DeFi)中,預言機(oracles)扮演著重要角色,它們是連接區塊鏈內智能合約和區塊鏈外現實世界資料的橋樑。當智能合約需要知道某個資產的市場價格時,它會向預言機請求資料。然而,如果攻擊者能夠操縱預言機提供的資料,就會導致合約做出錯誤的判斷,進而引發一系列災難性後果。
攻擊者可能會通過以下方式利用這個漏洞:
- 操縱預言機提供的價格資料,讓智能合約誤以為某個資產的價值發生了改變。
- 利用這些被操縱的價格,進行未經授權的借貸、超額槓桿交易,甚至耗盡流動性池。
漏洞範例
以下是一個存在漏洞的智能合約範例:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IPriceFeed {
function getLatestPrice() external view returns (int);
}
contract PriceOracleManipulation {
address public owner;
IPriceFeed public priceFeed;
constructor(address _priceFeed) {
owner = msg.sender;
priceFeed = IPriceFeed(_priceFeed);
}
function borrow(uint256 amount) public {
int price = priceFeed.getLatestPrice();
require(price > 0, "Price must be positive");
// Vulnerability: No validation or protection against price manipulation
uint256 collateralValue = uint256(price) * amount;
// Borrow logic based on manipulated price
// If an attacker manipulates the oracle, they could borrow more than they should
}
// Repayment logic
}
漏洞分析:
這個合約的 borrow
函數直接使用從預言機 priceFeed
獲取的價格,但沒有任何機制來驗證這個價格的真實性或合理性。如果攻擊者能操控 priceFeed
,將資產價格虛報,他們就能以較少的抵押品借出更多的資金。
影響
價格預言機操縱可能導致以下嚴重後果:
- 超額借貸:攻擊者可以虛報資產價格,讓合約誤以為其抵押品價值更高,從而借出遠超過實際價值的資金。
- 錯誤清算:當被操縱的價格導致抵押品被錯誤地低估時,可能使無辜的用戶在不該被清算時,卻被強制清算。
- 資金池枯竭:攻擊者可以利用被操縱的價格,在市場上進行套利,甚至耗盡合約中的流動性。
如何修復?
為了防範這類攻擊,可以採取以下補救措施:
- 多重預言機聚合:不要僅依賴單一預言機。可以從多個獨立且可靠的預言機獲取資料,然後取平均值或中位數,以降低單一來源被操縱的風險。
- 設定價格門檻:在合約中設定可接受的最低(minimum)和最高(maximum)價格範圍。如果預言機提供的價格超出這個範圍,則拒絕該筆交易。
- 時間鎖:在價格更新之間設置一個時間鎖,避免價格瞬間發生劇烈變化,給攻擊者可乘之機。
- 資料驗證:使用加密證明(如信任方簽名)來驗證預言機資料的真實性。
修復後的範例
以下是修復了上述漏洞的合約範例:
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IPriceFeed {
function getLatestPrice() external view returns (int);
}
contract PriceOracleManipulation {
address public owner;
IPriceFeed public priceFeed;
int public minPrice = 1000; // Set minimum acceptable price
int public maxPrice = 2000; // Set maximum acceptable price
function borrow(uint256 amount) public {
int price = priceFeed.getLatestPrice();
require(price > 0 && price >= minPrice && price <= maxPrice, "Price manipulation detected");
uint256 collateralValue = uint256(price) * amount;
// Borrow logic based on valid price
}
function repay(uint256 amount) public {
// Repayment logic
}
}
修復內容:
在修復後的版本中,borrow
函數在取得價格後,會先使用 require
語句檢查價格是否落在預設的 minPrice
和 maxPrice
範圍內。這樣一來,即使預言機被攻擊,合約也會因為價格不合理而拒絕執行,從而保護了合約的資產安全。
新增程式碼:int public minPrice = 1000;
// 設定可接受的最低價格
新增程式碼:int public maxPrice = 2000;
// 設定可接受的最高價格
新增程式碼:require(price > 0 && price >= minPrice && price <= maxPrice, "Price manipulation detected");
// 關鍵修復:新增價格驗證,確保價格在預設的範圍內