تمثل هجمات إعادة الدخول واحدة من أكثر الثغرات شهرة في أمان العقود الذكية، حيث تتسبب في سرقة ملايين الدولارات عبر بروتوكولات البلوكشين المختلفة. تستكشف هذه المقالة آلية ثغرات إعادة الدخول وتقدم تقنيات وقاية شاملة يجب على المطورين المهتمين بالأمان تنفيذها.
ما هو هجوم إعادة الدخول؟
في جوهرها، يحدث هجوم إعادة الدخول عندما يتم استدعاء دالة في عقد ذكي بشكل متكرر قبل أن تكتمل تنفيذها السابق. تنشأ الثغرة الأساسية عندما يستدعي عقد ذكي عقدًا خارجيًا قبل معالجة تغييرات حالته الخاصة، مما يخلق فرصة للاستغلال.
في سيناريو نموذجي، يتفاعل العقد A مع العقد B عن طريق استدعاء إحدى وظائفه. يظهر الخلل الأمني الحرج عندما يكتسب العقد B القدرة على الاتصال مرة أخرى بالعقد A بينما لا يزال العقد A ينفذ وظيفته الأصلية. تخلق هذه النمط التفاعلي التكراري الأساس لاستغلال محتمل.
كيف تعمل هجمات إعادة الدخول: تحليل خطوة بخطوة
اعتبر هذا السيناريو: العقد A يحتفظ بمجموع 10 ETH، حيث قام العقد B بإيداع 1 ETH في العقد A. تصبح الثغرة قابلة للاستغلال عندما يحاول العقد B سحب أمواله من خلال التسلسل التالي:
العقد B يستدعي وظيفة withdraw() في العقد A
العقد A يتحقق من أن رصيد العقد B أكبر من 0 (يمرر الفحص)
العقد A يرسل ETH إلى العقد B، مما يؤدي إلى تفعيل وظيفة الاسترجاع للعقد B
قبل أن يتمكن العقد A من تحديث رصيد العقد B إلى الصفر، تستدعي دالة الطوارئ في العقد B سحب () مرة أخرى
العقد A يتحقق من رصيد العقد B، الذي لا يزال يظهر 1 ETH (لم يتم تحديثه بعد)
تتكرر العملية حتى يتم استنزاف أموال العقد A
الضعف الرئيسي هو أن تحديث الرصيد يحدث بعد تحويل ETH، مما يسمح للمهاجم باستغلال نفس الرصيد عدة مرات قبل أن يتم ضبطه على الصفر.
تشريح الهجوم: التنفيذ الفني
لنلق نظرة على نمط الكود الضعيف:
صلابة
// عقد EtherStore المعرض للخطر
عقد EtherStore {
mapping(address = > uint) الأرصدة العامة ؛
وظيفة deposit() العامة مستحقة الدفع {
الأرصدة [msg.sender] += msg.value;
}
وظيفة withdrawAll() عامة {
uint bal = أرصدة [msg.sender];
require(bal > 0).
// الثغرة: استدعاء خارجي قبل تحديث الحالة
(bool تم إرسالها ، ) = msg.sender.call {value: bal}("");
require(sent, "فشل في إرسال الإيثر");
// تحديث الحالة يحدث متأخراً جداً
الأرصدة [msg.sender] = 0 ؛
}
}
الآن، دعونا نرى كيف يمكن للمهاجم استغلال هذه الثغرة:
صلابه
// عقد الهجوم الذي يستغل ثغرة إعادة الدخول
هجوم العقد {
EtherStore EtherStore العام ؛
constructor(address _etherStoreAddress) {
etherStore = EtherStore(_etherStoreAddress) ؛
}
// دالة الاحتياط التي يتم استدعاؤها عندما يرسل EtherStore الإيثر
استلام() قابل للدفع الخارجي {
IF(العنوان(etherStore).balance >= 1 ether) {
// إعادة إدخال دالة withdrawAll
etherStore.withdrawAll();
}
}
وظيفة attack() الخارج مستحق الدفع {
require(msg.value >= 1 ether) ؛
// إيداع لإنشاء رصيد في EtherStore
etherStore.deposit{القيمة: 1 إيثر} ();
// بدء عملية السحب، مما يؤدي إلى هجوم إعادة الدخول
etherStore.withdrawAll();
}
}
تبدأ سلسلة الهجوم عندما يقوم المهاجم باستدعاء attack(). يقوم هذا بإيداع 1 ETH لإنشاء رصيد ثم يستدعي withdrawAll(). عندما تعيد EtherStore إرسال ETH، يتم تفعيل وظيفة receive() في عقد الهجوم، والتي تستدعي withdrawAll() مرة أخرى قبل تحديث الرصيد. تستمر هذه الحلقة حتى يتم استنزاف أموال EtherStore.
تقنيات الوقاية الشاملة
يمكن للمطورين الذين يركزون على الأمان تنفيذ ثلاث تقنيات قوية لحماية ضد ثغرات إعادة الدخول:
1. حماية على مستوى الوظيفة: المعدل غير القابل للتكرار
أكثر وسائل الحماية شيوعًا على مستوى الوظيفة الفردية هي تنفيذ حارس إعادة الدخول:
صلابة
عقد ReentrancyGuard {
bool خاص مقفل = false;
المعدل غير قابل للإعادة() {
require(!مغلق, "استدعاء متكرر");
مقفل = صحيح;
_;
مقفلة = خطأ;
}
// قم بتطبيق هذا المعدل على الدوال الضعيفة
وظيفة سحب الأموال() عامة غير قابلة للتكرار {
// كود الدالة محمي من إعادة الدخول
}
}
هذه الطريقة تؤمن العقد خلال تنفيذ الدالة، مما يمنع أي استدعاءات تكرارية حتى تكتمل الدالة وتفتح الحالة.
2. حماية متعددة الوظائف: نمط الفحوصات-التأثيرات-التفاعلات
هذا النمط الأمني الأساسي يعيد هيكلة الكود لإزالة الثغرات عبر وظائف متعددة:
صلابة
// تنفيذ عرضة للخطر
وظيفة withdrawAll() عامة {
uint bal = أرصدة [msg.sender];
require(bal > 0).
(bool تم إرسالها ، ) = msg.sender.call {value: bal}("");
require(sent, "فشل في إرسال الإيثر");
balances[msg.sender] = 0; // تحديث الحالة بعد التفاعل
}
// تنفيذ آمن
وظيفة withdrawAll() عامة {
uint bal = أرصدة [msg.sender];
require(bal > 0). الشيكات
balances[msg.sender] = 0; // تأثيرات (تغييرات الحالة)
(bool تم إرسالها ، ) = msg.sender.call {value: bal}(""); التفاعلات
require(sent, "فشل في إرسال الإيثيريوم");
}
من خلال اتباع نمط Checks-Effects-Interactions، يقوم العقد بتحديث حالته قبل أي تفاعلات خارجية، مما يضمن أنه حتى إذا حاول المهاجم إعادة الدخول، فسيواجه الحالة المحدثة (رصيد صفري).
3. حماية على مستوى المشروع: حارس إعادة الدخول العالمي
بالنسبة للمشاريع المعقدة التي تحتوي على عقود متعددة تتفاعل مع بعضها البعض، فإن تنفيذ حارس إعادة الدخول العالمي يوفر حماية على مستوى النظام:
صلابه
عقد GlobalReentrancyGuard {
bool الخاصة _notEntered = صحيح ؛
// جميع العقود في المشروع ترث من GlobalReentrancyGuard
عقد SecureContract هو GlobalReentrancyGuard {
وظيفة vulnerableOperation() العامة globalNonReentrant {
// محمي من إعادة الدخول عبر المشروع بأكمله
}
}
تعتبر هذه الطريقة ذات قيمة خاصة في الحماية ضد هجمات إعادة الدخول عبر العقود في بروتوكولات التمويل اللامركزي حيث تتفاعل عقود متعددة مع بعضها البعض.
التأثير الواقعي لثغرات إعادة الدخول
أدت ثغرات إعادة الدخول إلى بعض من أكثر الاستغلالات تدميراً في تاريخ blockchain. أدى اختراق DAO الشهير في عام 2016 إلى سرقة حوالي 3.6 مليون ETH بقيمة حوالي ( مليون في ذلك الوقت، مما أدى في النهاية إلى انقسام Ethereum الصعب الذي أنشأ Ethereum Classic.
مؤخراً، في عام 2020، فقد بروتوكول Lendf.Me حوالي $50 مليون نتيجة لهجوم إعادة الدخول، مما يبرز أنه على الرغم من زيادة الوعي، لا تزال هذه الثغرات تمثل مخاطر كبيرة على أمان العقود الذكية.
أفضل الممارسات الأمنية
بجانب التقنيات المحددة المذكورة، ينبغي على المطورين اتباع هذه الممارسات الأمنية الإضافية:
استخدم دائمًا أحدث إصدار من Solidity الذي يقدم ميزات أمان محسّنة
تخضع العقود للمدققين الأمنيين الشاملين من قبل شركات ذات سمعة طيبة
تنفيذ تغطية اختبار شاملة بما في ذلك اختبارات الوحدة لحالات الحافة
ابدأ بتعرض الحد الأدنى من ETH عند نشر العقود الجديدة في الإنتاج
اعتبر التحقق الرسمي للعقود عالية القيمة
من خلال تنفيذ هذه التقنيات الدفاعية واتباع أفضل الممارسات الأمنية، يمكن للمطورين تقليل خطر هجمات إعادة الدخول بشكل كبير وبناء عقود ذكية أكثر أمانًا لتطبيقات البلوكتشين.
قد تحتوي هذه الصفحة على محتوى من جهات خارجية، يتم تقديمه لأغراض إعلامية فقط (وليس كإقرارات/ضمانات)، ولا ينبغي اعتباره موافقة على آرائه من قبل Gate، ولا بمثابة نصيحة مالية أو مهنية. انظر إلى إخلاء المسؤولية للحصول على التفاصيل.
هجمات إعادة الدخول في العقود الذكية: فهم الثغرة وتنفيذ استراتيجيات الوقاية
تمثل هجمات إعادة الدخول واحدة من أكثر الثغرات شهرة في أمان العقود الذكية، حيث تتسبب في سرقة ملايين الدولارات عبر بروتوكولات البلوكشين المختلفة. تستكشف هذه المقالة آلية ثغرات إعادة الدخول وتقدم تقنيات وقاية شاملة يجب على المطورين المهتمين بالأمان تنفيذها.
ما هو هجوم إعادة الدخول؟
في جوهرها، يحدث هجوم إعادة الدخول عندما يتم استدعاء دالة في عقد ذكي بشكل متكرر قبل أن تكتمل تنفيذها السابق. تنشأ الثغرة الأساسية عندما يستدعي عقد ذكي عقدًا خارجيًا قبل معالجة تغييرات حالته الخاصة، مما يخلق فرصة للاستغلال.
في سيناريو نموذجي، يتفاعل العقد A مع العقد B عن طريق استدعاء إحدى وظائفه. يظهر الخلل الأمني الحرج عندما يكتسب العقد B القدرة على الاتصال مرة أخرى بالعقد A بينما لا يزال العقد A ينفذ وظيفته الأصلية. تخلق هذه النمط التفاعلي التكراري الأساس لاستغلال محتمل.
كيف تعمل هجمات إعادة الدخول: تحليل خطوة بخطوة
اعتبر هذا السيناريو: العقد A يحتفظ بمجموع 10 ETH، حيث قام العقد B بإيداع 1 ETH في العقد A. تصبح الثغرة قابلة للاستغلال عندما يحاول العقد B سحب أمواله من خلال التسلسل التالي:
الضعف الرئيسي هو أن تحديث الرصيد يحدث بعد تحويل ETH، مما يسمح للمهاجم باستغلال نفس الرصيد عدة مرات قبل أن يتم ضبطه على الصفر.
تشريح الهجوم: التنفيذ الفني
لنلق نظرة على نمط الكود الضعيف:
صلابة // عقد EtherStore المعرض للخطر عقد EtherStore { mapping(address = > uint) الأرصدة العامة ؛
}
الآن، دعونا نرى كيف يمكن للمهاجم استغلال هذه الثغرة:
صلابه // عقد الهجوم الذي يستغل ثغرة إعادة الدخول هجوم العقد { EtherStore EtherStore العام ؛
}
تبدأ سلسلة الهجوم عندما يقوم المهاجم باستدعاء attack(). يقوم هذا بإيداع 1 ETH لإنشاء رصيد ثم يستدعي withdrawAll(). عندما تعيد EtherStore إرسال ETH، يتم تفعيل وظيفة receive() في عقد الهجوم، والتي تستدعي withdrawAll() مرة أخرى قبل تحديث الرصيد. تستمر هذه الحلقة حتى يتم استنزاف أموال EtherStore.
تقنيات الوقاية الشاملة
يمكن للمطورين الذين يركزون على الأمان تنفيذ ثلاث تقنيات قوية لحماية ضد ثغرات إعادة الدخول:
1. حماية على مستوى الوظيفة: المعدل غير القابل للتكرار
أكثر وسائل الحماية شيوعًا على مستوى الوظيفة الفردية هي تنفيذ حارس إعادة الدخول:
صلابة عقد ReentrancyGuard { bool خاص مقفل = false;
}
هذه الطريقة تؤمن العقد خلال تنفيذ الدالة، مما يمنع أي استدعاءات تكرارية حتى تكتمل الدالة وتفتح الحالة.
2. حماية متعددة الوظائف: نمط الفحوصات-التأثيرات-التفاعلات
هذا النمط الأمني الأساسي يعيد هيكلة الكود لإزالة الثغرات عبر وظائف متعددة:
صلابة // تنفيذ عرضة للخطر وظيفة withdrawAll() عامة { uint bal = أرصدة [msg.sender]; require(bal > 0).
}
// تنفيذ آمن وظيفة withdrawAll() عامة { uint bal = أرصدة [msg.sender]; require(bal > 0). الشيكات
}
من خلال اتباع نمط Checks-Effects-Interactions، يقوم العقد بتحديث حالته قبل أي تفاعلات خارجية، مما يضمن أنه حتى إذا حاول المهاجم إعادة الدخول، فسيواجه الحالة المحدثة (رصيد صفري).
3. حماية على مستوى المشروع: حارس إعادة الدخول العالمي
بالنسبة للمشاريع المعقدة التي تحتوي على عقود متعددة تتفاعل مع بعضها البعض، فإن تنفيذ حارس إعادة الدخول العالمي يوفر حماية على مستوى النظام:
صلابه عقد GlobalReentrancyGuard { bool الخاصة _notEntered = صحيح ؛
}
// جميع العقود في المشروع ترث من GlobalReentrancyGuard عقد SecureContract هو GlobalReentrancyGuard { وظيفة vulnerableOperation() العامة globalNonReentrant { // محمي من إعادة الدخول عبر المشروع بأكمله } }
تعتبر هذه الطريقة ذات قيمة خاصة في الحماية ضد هجمات إعادة الدخول عبر العقود في بروتوكولات التمويل اللامركزي حيث تتفاعل عقود متعددة مع بعضها البعض.
التأثير الواقعي لثغرات إعادة الدخول
أدت ثغرات إعادة الدخول إلى بعض من أكثر الاستغلالات تدميراً في تاريخ blockchain. أدى اختراق DAO الشهير في عام 2016 إلى سرقة حوالي 3.6 مليون ETH بقيمة حوالي ( مليون في ذلك الوقت، مما أدى في النهاية إلى انقسام Ethereum الصعب الذي أنشأ Ethereum Classic.
مؤخراً، في عام 2020، فقد بروتوكول Lendf.Me حوالي $50 مليون نتيجة لهجوم إعادة الدخول، مما يبرز أنه على الرغم من زيادة الوعي، لا تزال هذه الثغرات تمثل مخاطر كبيرة على أمان العقود الذكية.
أفضل الممارسات الأمنية
بجانب التقنيات المحددة المذكورة، ينبغي على المطورين اتباع هذه الممارسات الأمنية الإضافية:
من خلال تنفيذ هذه التقنيات الدفاعية واتباع أفضل الممارسات الأمنية، يمكن للمطورين تقليل خطر هجمات إعادة الدخول بشكل كبير وبناء عقود ذكية أكثر أمانًا لتطبيقات البلوكتشين.