الإصدار السريع: إعادة الدخول تشبه هاكر يتصل بك مجددًا بينما لا تزال تقوم بتحويل المال إليهم - يقومون بتفريغ محفظتك قبل أن تكتمل المعاملة.
هذه هي الحقيقة القاسية: تم فقدان أكثر من $100M بسبب استغلالات إعادة الدخول. الأكثر شهرة؟ اختراق DAO (2016) سرق $50M من ETH من خلال استغلال هذه الثغرة بالذات.
كيف يعمل الهجوم ( باستخدام منطق الشيفرة الحقيقية )
تخيل أن العقد ContractA يحتفظ بـ 10 ETH والعقد ContractB لديه رصيد 1 ETH مخزّن داخله.
عندما يقوم ContractB باستدعاء withdrawAll()، يجب أن يحدث ما يلي:
تحقق من الرصيد > 0 ✓
أرسل ETH مرة أخرى ✓
تحديث الرصيد إلى 0 ✓
لكن هنا حيث ينكسر الأمر: المهاجم يستغل ترتيب العمليات.
تدفق الاستغلال:
المهاجم يستدعي attack() → والذي يستدعي withdrawAll() على ContractA
ContractA يرسل 1 ETH ويقوم بتفعيل وظيفة الاسترجاع للمهاجم ()
قبل تحديث الرصيد إلى 0، يتم استدعاء fallback() مرة أخرى على الفور withdrawAll()
ContractA يتحقق: “هل الرصيد > 0؟” نعم ( لأنه لم يتم تحديثه بعد!)
يرسل 1 إيثريوم آخر → يُشغل fallback() مرة أخرى
تستمر هذه الحلقة حتى يتم استنزاف ContractA بالكامل
رؤية رئيسية: يحدث تحديث الرصيد بعد تحويل الإيثريوم. هذه هي نافذة الضعف.
ثلاث استراتيجيات للدفاع
1. غير القابل لإعادة الدخول المعدل (حماية الوظيفة الفردية)
قم بقفل الوظيفة أثناء تنفيذها. لا يُسمح بإعادة الدخول:
صلابة
المعدل غير القابل للتكرار {
require(!locked, “لا إعادة الدخول”);
مغلق = صحيح;
_;
مقفلة = خاطئة;
}
بسيط، لكنه يحمي وظيفة واحدة فقط في كل مرة.
2. نمط الفحوصات-التأثيرات-التفاعلات (حماية متعددة الوظائف)
هذه هي النقطة المحورية:
التحقق: تحقق من الشروط (الرصيد > 0)
التأثيرات: تحديث الحالة (الرصيد = 0) ← نقل هذا قبل إرسال ETH
التفاعلات: إرسال ETH
ترتيب خاطئ:
require(balance > 0).
→ إرسال ETH
→ الرصيد = 0; // لقد فات الأوان!
الترتيب الصحيح:
require(balance > 0).
→ الرصيد = 0; // تحديث أول
→ أرسل ETH // ثم تفاعل
الآن حتى إذا عادت fallback()، فإن الرصيد بالفعل 0. الهجوم يفشل.
3. GlobalReentrancyGuard (حماية عبر العقود)
لأنظمة معقدة تحتوي على عقود متعددة تتفاعل مع بعضها البعض، استخدم عقد حراسة مركزي يتتبع حالة القفل عبر جميع العقود. عندما يستدعي ContractA ContractB، يسجل الحارس ذلك - إذا حاول ContractB العودة إلى النظام قبل العودة، فإن الحارس يمنع ذلك.
لماذا هذا مهم
إعادة الدخول ليست مجرد مشكلة في Solidity - إنها مشكلة تصميم. في كل مرة ترسل فيها ETH أو تستدعي وظائف خارجية، فإنك تسلم السيطرة إلى كود غير موثوق. وظيفة العودة للمهاجم تعمل في سياق عقدك.
البيانات: وجدت Chainalysis أن حوالي 60% من الاستغلالات عالية القيمة في 2023-2024 تضمنت إعادة الدخول أو أنماط مماثلة. كانت المشاريع الرائدة مثل Yearn و Curve و Balancer جميعها تواجه مخاوف من إعادة الدخول.
الخط السفلي: استخدم نمط التحقق من التأثيرات والتفاعلات كقاعدة. أضف nonReentrant حيثما دعت الحاجة. بالنسبة للأنظمة المتعددة العقود، نفّذ GlobalReentrancyGuard. كان من الممكن إنقاذ أكثر من 100 مليون دولار باستخدام هذه الأنماط الأساسية.
تابع @TheBlockChainer لمزيد من الغوص العميق في أمان الويب 3.
قد تحتوي هذه الصفحة على محتوى من جهات خارجية، يتم تقديمه لأغراض إعلامية فقط (وليس كإقرارات/ضمانات)، ولا ينبغي اعتباره موافقة على آرائه من قبل Gate، ولا بمثابة نصيحة مالية أو مهنية. انظر إلى إخلاء المسؤولية للحصول على التفاصيل.
هجوم إعادة الدخول: لماذا يتم استنزاف العقود الذكية باستمرار ( وكيفية إيقاف ذلك )
الإصدار السريع: إعادة الدخول تشبه هاكر يتصل بك مجددًا بينما لا تزال تقوم بتحويل المال إليهم - يقومون بتفريغ محفظتك قبل أن تكتمل المعاملة.
هذه هي الحقيقة القاسية: تم فقدان أكثر من $100M بسبب استغلالات إعادة الدخول. الأكثر شهرة؟ اختراق DAO (2016) سرق $50M من ETH من خلال استغلال هذه الثغرة بالذات.
كيف يعمل الهجوم ( باستخدام منطق الشيفرة الحقيقية )
تخيل أن العقد ContractA يحتفظ بـ 10 ETH والعقد ContractB لديه رصيد 1 ETH مخزّن داخله.
عندما يقوم ContractB باستدعاء withdrawAll()، يجب أن يحدث ما يلي:
لكن هنا حيث ينكسر الأمر: المهاجم يستغل ترتيب العمليات.
تدفق الاستغلال:
رؤية رئيسية: يحدث تحديث الرصيد بعد تحويل الإيثريوم. هذه هي نافذة الضعف.
ثلاث استراتيجيات للدفاع
1. غير القابل لإعادة الدخول المعدل (حماية الوظيفة الفردية)
قم بقفل الوظيفة أثناء تنفيذها. لا يُسمح بإعادة الدخول: صلابة المعدل غير القابل للتكرار { require(!locked, “لا إعادة الدخول”); مغلق = صحيح; _; مقفلة = خاطئة; }
بسيط، لكنه يحمي وظيفة واحدة فقط في كل مرة.
2. نمط الفحوصات-التأثيرات-التفاعلات (حماية متعددة الوظائف)
هذه هي النقطة المحورية:
ترتيب خاطئ:
require(balance > 0). → إرسال ETH → الرصيد = 0; // لقد فات الأوان!
الترتيب الصحيح:
require(balance > 0). → الرصيد = 0; // تحديث أول → أرسل ETH // ثم تفاعل
الآن حتى إذا عادت fallback()، فإن الرصيد بالفعل 0. الهجوم يفشل.
3. GlobalReentrancyGuard (حماية عبر العقود)
لأنظمة معقدة تحتوي على عقود متعددة تتفاعل مع بعضها البعض، استخدم عقد حراسة مركزي يتتبع حالة القفل عبر جميع العقود. عندما يستدعي ContractA ContractB، يسجل الحارس ذلك - إذا حاول ContractB العودة إلى النظام قبل العودة، فإن الحارس يمنع ذلك.
لماذا هذا مهم
إعادة الدخول ليست مجرد مشكلة في Solidity - إنها مشكلة تصميم. في كل مرة ترسل فيها ETH أو تستدعي وظائف خارجية، فإنك تسلم السيطرة إلى كود غير موثوق. وظيفة العودة للمهاجم تعمل في سياق عقدك.
البيانات: وجدت Chainalysis أن حوالي 60% من الاستغلالات عالية القيمة في 2023-2024 تضمنت إعادة الدخول أو أنماط مماثلة. كانت المشاريع الرائدة مثل Yearn و Curve و Balancer جميعها تواجه مخاوف من إعادة الدخول.
الخط السفلي: استخدم نمط التحقق من التأثيرات والتفاعلات كقاعدة. أضف nonReentrant حيثما دعت الحاجة. بالنسبة للأنظمة المتعددة العقود، نفّذ GlobalReentrancyGuard. كان من الممكن إنقاذ أكثر من 100 مليون دولار باستخدام هذه الأنماط الأساسية.
تابع @TheBlockChainer لمزيد من الغوص العميق في أمان الويب 3.