العقود الآجلة
وصول إلى مئات العقود الدائمة
TradFi
الذهب
منصّة واحدة للأصول التقليدية العالمية
الخیارات المتاحة
Hot
تداول خيارات الفانيلا على الطريقة الأوروبية
الحساب الموحد
زيادة كفاءة رأس المال إلى أقصى حد
التداول التجريبي
مقدمة حول تداول العقود الآجلة
استعد لتداول العقود الآجلة
أحداث مستقبلية
"انضم إلى الفعاليات لكسب المكافآت "
التداول التجريبي
استخدم الأموال الافتراضية لتجربة التداول بدون مخاطر
إطلاق
CandyDrop
اجمع الحلوى لتحصل على توزيعات مجانية.
منصة الإطلاق
-التخزين السريع، واربح رموزًا مميزة جديدة محتملة!
HODLer Airdrop
احتفظ بـ GT واحصل على توزيعات مجانية ضخمة مجانًا
منصة الإطلاق
كن من الأوائل في الانضمام إلى مشروع التوكن الكبير القادم
نقاط Alpha
تداول الأصول على السلسلة واكسب التوزيعات المجانية
نقاط العقود الآجلة
اكسب نقاط العقود الآجلة وطالب بمكافآت التوزيع المجاني
أردت فقط مشاركة مشكلة أمنية في العقود الذكية التي لا زال العديد من المطورين يتجاهلونها — وهي هجوم 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 وكيفية الحماية منه سيساعدك على بناء عقود ذكية أكثر أمانًا بكثير.