أردت فقط مشاركة مشكلة أمنية في العقود الذكية التي لا زال العديد من المطورين يتجاهلونها — وهي هجوم reentrancy. إذا كنت تبني عقدًا ذكيًا على Solidity، فهذه مسألة يجب أن تفهمها جيدًا.



ببساطة، يحدث reentrancy عندما يستدعي عقدٌ عقدًا آخر، ويمكن لذلك العقد أن يستدعي مرة أخرى العقد الأصلي أثناء تنفيذه. تخيل أن لديك ContractA يحتوي على 10 Ether، وContractB يرسل إليه 1 Ether. عندما يقوم ContractB بسحب الأموال، يتحقق ContractA من أن الرصيد أكبر من 0، وإذا كان كذلك، يرسل Ether. لكن، إذا كان ContractB لديه وظيفة fallback(، فهي وظيفة احتياطية يمكنها استدعاء وظيفة السحب في ContractA أثناء تنفيذها، قبل أن تكتمل. النتيجة؟ يظل رصيد ContractB يُحتسب على أنه 1 Ether، وبالتالي يمكنه استلام 1 Ether أخرى، وهكذا يتكرر الأمر حتى ينفد ContractA.

كيف يعمل هذا الهجوم؟ المهاجم يحتاج إلى شيئين: وظيفة attack) لبدء الهجوم، ووظيفة fallback لاستدعاء وظيفة السحب مرة أخرى. وظيفة fallback هي وظيفة خارجية خاصة، لا اسم لها، ولا تتطلب معلمات، ويمكن لأي شخص تفعيلها عبر استدعاء وظيفة غير موجودة، أو إرسال Ether بدون بيانات.

هناك مثال محدد: عقد EtherStore لديه وظيفة deposit( لتخزين الرصيد، ووظيفة withdrawAll) لسحب كل الأموال. المشكلة أن withdrawAll( يتحقق من الرصيد، يرسل Ether، ثم يحدث تحديث الرصيد إلى 0. هذا يخلق فجوة تسمح بحدوث هجوم reentrancy.

كيف نُحمي أنفسنا؟ سأذكر ثلاث طرق.

الأولى، استخدام modifier noReentrant. الفكرة بسيطة جدًا: نقفل العقد أثناء تنفيذ الوظيفة. إذا حاول أحد استدعاء الوظيفة مرة أخرى، يجب أن يتجاوز فحص القفل، لكن القفل لن يُفتح إلا بعد اكتمال التنفيذ. الـ modifier هو نوع خاص من الوظائف يتيح لك إضافة شروط إلى وظائف أخرى دون إعادة كتابة المنطق بالكامل.

الثانية، تطبيق نمط Check-Effect-Interaction. بدلاً من التحقق من الشرط، وإرسال الأموال، ثم تحديث الرصيد، يجب أن تتحقق أولاً، وتقوم بتحديث الرصيد فورًا) قبل إرسال الأموال(، ثم تتفاعل مع الطرف الخارجي. بهذه الطريقة، حتى لو حدث reentrancy، يكون الرصيد قد تم تحديثه إلى 0، ولن يتمكن المهاجم من سحب المزيد.

الثالثة، إذا كان مشروعك يتضمن العديد من العقود التي تتفاعل مع بعضها، فاستعمل GlobalReentrancyGuard. بدلاً من قفل وظيفة واحدة، تقفل النظام بأكمله باستخدام متغير حالة مخزن في عقد مستقل. عندما يتم استدعاء أي وظيفة في أي عقد، يتحقق من حالة القفل. إذا كان مقفلاً، يتم رفض المعاملة. هذا مفيد جدًا إذا كانت لديك عقود مثل ScheduledTransfer التي ترسل أموالًا إلى AttackTransfer — فـGlobalReentrancyGuard يمنع حدوث سلسلة هجمات reentrancy كاملة.

الميزة في هذه الطرق الثلاثة أنها يمكن دمجها حسب الحالة. وظيفة مهمة؟ استخدم noReentrant. وظائف متعددة مرتبطة؟ استخدم Check-Effect-Interaction. مشروع كبير ومعقد؟ استخدم GlobalReentrancyGuard. فهم reentrancy وكيفية الحماية منه سيساعدك على بناء عقود ذكية أكثر أمانًا بكثير.
شاهد النسخة الأصلية
قد تحتوي هذه الصفحة على محتوى من جهات خارجية، يتم تقديمه لأغراض إعلامية فقط (وليس كإقرارات/ضمانات)، ولا ينبغي اعتباره موافقة على آرائه من قبل Gate، ولا بمثابة نصيحة مالية أو مهنية. انظر إلى إخلاء المسؤولية للحصول على التفاصيل.
  • أعجبني
  • تعليق
  • إعادة النشر
  • مشاركة
تعليق
إضافة تعليق
إضافة تعليق
لا توجد تعليقات
  • Gate Fun الساخن

    عرض المزيد
  • القيمة السوقية:$2.23Kعدد الحائزين:1
    0.00%
  • القيمة السوقية:$2.23Kعدد الحائزين:0
    0.00%
  • القيمة السوقية:$2.23Kعدد الحائزين:1
    0.00%
  • القيمة السوقية:$0.1عدد الحائزين:1
    0.00%
  • القيمة السوقية:$2.23Kعدد الحائزين:0
    0.00%
  • تثبيت