مقدمة
إن شركتنا تعمل في مجال التدقيق الأمني للعقود الذكية ، وقضية استخدام الأدوات الآلية شديدة الحدة. كم يمكن أن يساعدوا في تحديد الأماكن المشبوهة ، والأماكن التي يجب استخدامها ، وما الذي يمكنهم فعله وما هي تفاصيل العمل في هذا المجال؟ هذه والقضايا ذات الصلة هي موضوع هذه المادة. وستكون المواد عبارة عن محاولات للعمل بعقود حقيقية بمساعدة الممثلين والوصفات الأكثر إثارة للاهتمام لإطلاق هذا البرنامج الشيق للغاية والمثير للاهتمام للغاية. في البداية أردت أن أصنع مقالًا واحدًا ، لكن بعد مرور بعض الوقت أصبحت كمية المعلومات أكبر من اللازم ، لذلك تقرر إنشاء سلسلة من المقالات ، واحدة لكل محلل تلقائي. يتم تقديم القائمة التي سنتخذ منها الأدوات ، على سبيل المثال ، هنا ، ولكن إذا ظهرت أدوات أخرى مثيرة للاهتمام أثناء الكتابة ، فسوف أصفها بكل سرور واختبرها.
يجب أن أقول أن مهام التدقيق كانت مثيرة للاهتمام للغاية ، لأنه حتى الآن ، لم يهتم المطورون كثيرًا بالجوانب الاقتصادية للخوارزميات ، والتحسين الداخلي. وقد أضاف تدقيق العقود الذكية العديد من متجهات الهجوم المثيرة للاهتمام التي يجب مراعاتها عند البحث عن الأخطاء. أيضًا ، كما اتضح فيما بعد ، ظهرت العديد من الأدوات للاختبار التلقائي: أجهزة التحليل الثابتة ، ومحللات شفرة الشفرة ، والألغاز ، والمحللات ، والعديد من البرامج الجيدة الأخرى.
الغرض من هذه المقالة: تعزيز توزيع رمز عقد آمن والسماح للمطورين بالتخلص بسرعة وسهولة من الأخطاء الغبية ، والتي غالبًا ما تكون أكثر إزعاجًا. عندما يكون البروتوكول نفسه موثوقًا تمامًا ويؤدي إلى حل مشكلة خطيرة ، فإن وجود خطأ غبي منسي في مرحلة الاختبار يمكن أن يدمر حياة المشروع بشكل خطير. لذلك ، دعونا نتعلم استخدام ، على الأقل ، الأدوات التي تسمح لـ "القليل من الدم" بالتخلص من المشكلات المعروفة.
التطلع إلى المستقبل ، يجب أن أقول إن الأخطاء الشائعة الأكثر شيوعًا التي واجهناها في عمليات التدقيق لا تزال تمثل مشكلات منطقية في التنفيذ ، وليست نقاط ضعف نموذجية مثل حقوق الوصول وتجاوز عدد صحيح وإعادة الدخول. من المستحيل إجراء مراجعة كبيرة وكاملة للحلول دون وجود مطورين ذوي خبرة قادرين على تدقيق المنطق العالي المستوى للعقود ودورة حياتهم وجوانب التشغيل الفعلي والامتثال للمهمة وليس فقط أنماط الهجوم المعتادة. إنه منطق رفيع المستوى غالبًا ما يصبح مصدرًا للأخطاء الحرجة.
لكن التحذيرات والثقوب النموذجية والأخطاء التي تُركت بسبب الإهمال التي لا ينبغي تفويتها هي مصير المحللون الأوتوماتيين ، وعليهم التعامل مع هذه المهام بشكل أفضل من الناس. هذه هي الفرضية التي سيتم اختبارها.
ميزات مراجعة قانون العقود الذكية
تعد مراجعة كود العقود الذكية مجالًا محددًا إلى حد ما. على الرغم من صغر حجمه ، فإن عقد Ethereum الذكي هو برنامج متكامل يمكنه تنظيم الفروع المعقدة ، والحلقات ، وأشجار القرار ، وحتى لأتمتة المعاملات البسيطة التي تتطلب التفكير في جميع الفروع الممكنة في كل خطوة. من وجهة النظر هذه ، يكون تطوير blockchain منخفض المستوى للغاية ، ويتطلب الكثير من الموارد ويذكرنا جدًا بتطوير النظام والبرامج المدمجة بلغات C / C ++ ولغات المجمّع. هذا هو السبب في أننا نحب أن نرى في المقابلات مطوري الخوارزميات ذات المستوى المنخفض ، ومكدس الشبكة ، والخدمات المحملة للغاية ، وكل من تعامل مع تحسين المستوى المنخفض ومراجعة الكود.
من وجهة نظر المطور ، تعتبر Solidity أيضًا محددة تمامًا ، على الرغم من أنه يسهل قراءتها من قِبل أي مبرمج تقريبًا وفي الخطوات الأولى ويبدو بسيطًا للغاية. كود Solidity سهل القراءة إلى حد ما ، ومن المعروف أن أي مطور يعرف بناء جملة C / C ++ و OOP ، مثل JavaScript.
هنا بساطة الكود هي مفتاح البقاء ، لا شيء ثقيل ، لذلك يتم استخدام ترسانة كاملة من التطوير المنخفض المستوى في العمل - الخوارزميات التي تسمح بالاستخدام الفعال للموارد ، حفظ الذاكرة: أشجار Merkle ، مرشحات Bloom ، تحميل المورد "الكسول" ، حلقات إلغاء التحميل ، تجميع القمامة اليدوي وأكثر من ذلك بكثير.
كمية صغيرة من الكود المصدري و bytecode الناتج.
يقتصر العقد الذكي المنفصل على حجم البايت كود ، وكل بايت يتكلف كمية معينة من الغاز ، والحد الأقصى محدود من أعلاه ، حتى تتمكن من دفع حوالي 10 كيلو بايت في سلسلة الكتل (في الوقت الحالي) ، لن تنجح بعد الآن. فيما يلي مقال جيد حول مقدار تكاليف نشر العقد وكمية تكاليف الغاز . لذلك ، لا يمكن دفع الكثير. إذا المبالغة ، فإن عدة آلاف من الأسطر من الكود "المتوسط" هي الحد الأقصى. عدة عشرات من الأساليب ، وعدم وجود التجميع والمنطق المعقدة عموما هي سمة للغاية من العقود. كل ما لا يناسبك يتطلب منك تحديد الشفرة في مكتبات منفصلة ، لتغيير وتعقد إجراءات التحميل على الشبكة. قد يكون مطورو Solidity سعداء بدفع مجموعة من التعليمات البرمجية في عقد واحد ، لكن عليهم ببساطة ترتيب أنظمة العقود الخاصة بهم بشكل صحيح عن طريق إنشاء مكتبات فصل منفصلة مع تخزينهم الخاص. ومن المريح تحليل هذه "الفئات" المنفصلة في ملفات منفصلة ، وبالتالي ، فإن قراءة رمز العقود جميل ، كل شيء منظم بشكل جيد من البداية - لن ينجح الأمر على خلاف ذلك. على سبيل المثال ، أوصي بالنظر في كيفية صنع ERC721 في صلابة openzeppelin .
الغاز ، الغاز ، الغاز
تقدم Gas طبقة إضافية من المنطق في تنفيذ رمز العقد ، الأمر الذي يتطلب مراجعة. علاوة على ذلك ، على عكس الشفرة التقليدية ، يمكن لقسم الشفرة نفسه أن ينفق كميات مختلفة من الغاز. إن جدول رموز EVM وتكلفتها مفيد لفهم قيود الغاز.
لتوضيح سبب تكريسك الكثير من الوقت لتقييم الغاز ، فكر في هذا الجزء من الشفرة الزائفة (بالطبع ، غير واقعي ؛ إطلاق النار في الحلقة مع الأثير فكرة سيئة):
// function fixSomeAccountAction(uint _actionId) public onlyValidator { // … events[msg.sender].push(_actionId); } // , function receivePaymentForSavedActions() { // ... for (uint256 i = 0; i < events[msg.sender].length; i++) { // actionId uint actionId = events[msg.sender][i]; // action uint payment = getPriceByEventId(actionId); if (payment > 0) { paymentAccumulators[msg.sender] += payment; } emit LogEventPaymentForAction(msg.sender, actionId, payment); // … // delete “events[msg.sender][i]” from array } }
الحقيقة هي أن الدورة في العقد يتم تنفيذها أحداث [msg.sender] .length الأوقات ، وكل تكرار هو إدخال في blockchain (transfer () و emit ()). إذا كان طول المصفوفة صغيرًا ، فإن الدورة تفي بعشر مرات ، وتوزع الدفع لكل إجراء. ولكن ، إذا كانت مجموعة الأحداث [msg.sender] كبيرة ، فستكون هناك العديد من التكرارات وسيتم تشغيل الغاز المستهلك إلى الحد الأقصى للغاز الثابت المرمّز (حوالي 8،000،000). ستنخفض المعاملة ولن تنجح أبدًا ، حيث لا توجد طريقة لتقليل طول مجموعة الأحداث [msg.sender] في العقد. إذا كانت الدورة لا تحسب فقط قيمة الوحدة ، ولكنها تكتب إلى blockchain (على سبيل المثال ، يتم دفع بعض الرسوم ، ودفعات مقابل الإجراءات) ، فإن عدد التكرار المسموح به محدود للغاية. القاضي لنفسك - الحد الأقصى: 8000000 ، تسجيل قيمة 256 بت جديدة: 20،000. يمكنك حفظ أو تحديث البيانات الوصفية فقط لبضع مئات من عناوين 256 بت مع بعض البيانات الوصفية ، والجزء الممتع الآخر هو كتابة قيمة جديدة: 20،000 ، وتحديث واحد موجود: 5000 ، لذلك حتى مع نفس بيئة العقد بالضبط عند إجراء عملية نقل الرموز المميزة لعنوان يحتوي على رموز بالفعل ، تنفق أقل 4 مرات من الغاز (5000 مقابل 20000) على رقم قياسي.
لذلك ، لا تتفاجأ من أن مسألة الغاز في العقود الذكية ترتبط ارتباطًا وثيقًا بأمان العقود ، لأن الموقف عندما تكون الأموال عالقة بشكل دائم في العقد من الناحية العملية لا يختلف كثيرًا عن الموقف عند سرقته. حقيقة أن تعليمات ADD تكلف 3 غاز و SSTORE (توفير في التخزين): 20 000 يعني أن أغلى مورد في blockchain هو التخزين ، ومهام تحسين رمز العقد لها الكثير من القواسم المشتركة مع مهام التطوير منخفضة المستوى في C و ASM المدمجة أنظمة ، حيث التخزين هو أيضا مورد محدود للغاية.
blockchain جميلة
هذه فقرة إيجابية جدًا حول سبب كون blockchain جيدًا من وجهة نظر الأمان للمدقق فقط. الحتمية لتنفيذ رمز العقد هو مفتاح تصحيح الأخطاء الناجح وتشغيل الأخطاء والثغرات الأمنية. من الناحية الفنية ، يمكن إعادة إنتاج أي مكالمة إلى رمز العقد على أي منصة بدقة عالية ، وهذا يسمح للاختبارات بالعمل في كل مكان ويكون من السهل للغاية دعمه ، والتحقيق في الحوادث يمكن الاعتماد عليه ولا يمكن إنكاره. الآن نحن نعرف دائمًا من الذي تم استدعاء الوظيفة فيه ، وما هي المعلمات ، وما هي الكود الذي عالجتها والنتيجة. كل هذا مصمم بالكامل ، أي يلعب في أي مكان ، حتى في JS على صفحة ويب. إذا تحدثنا عن Ethereum ، فمن السهل للغاية كتابة أي حالة اختبار في جافا سكريبت مريحة ، بما في ذلك المعلمات المزيفة ، وتعمل بشكل رائع أينما توجد Node.js.
ومع ذلك ، يجب ألا تهدئ كل هذه الكلمات الجميلة المطورين ، لأنه كما ذكر أعلاه ، فإن أخطر الأخطاء منطقية ، ولهم أن حتمية التنفيذ هي خاصية متعامدة.
البيئة لتجميع العقد
لكتابة المقال ، حصلت على عقد تجريبي قديم لحجز منزل من مصمم Smartz: https://github.com/smartzplatform/constructor-eth-booking . يسمح لك العقد بإنشاء سجل للكائن (الشقة أو غرفة الفندق) ، وتحديد السعر وتواريخ التسليم ، وبعد ذلك ينتظر العقد للدفع ، وإذا تم استلامه ، يعمل على إصلاح قانون الحجز ، مع الاحتفاظ بالأموال على الرصيد حتى يدخل الضيف الغرفة و لن تأكيد الدخول. في هذه المرحلة ، يتلقى مالك الغرفة الدفع. العقد هو في الأساس آلة دولة ، ويمكن الاطلاع على الحالات والانتقالات في Booking.sol. لقد قمنا بذلك بسرعة ، وقمنا بتغييره أثناء عملية التطوير ولم نتمكن من القيام بعدد كبير من الاختبارات ، وهو بعيد عن الإصدار الجديد من المترجم ومنطق داخلي أكثر أو أقل ثراءً. لذلك دعونا نرى كيف يتعامل المحللون معها ، وما هي الأخطاء التي سيجدونها ، وإذا لزم الأمر ، نضيف أخطائنا.
العمل مع إصدارات مختلفة من solc
سيتعين استخدام محللات مختلفة بطرق مختلفة - يتم إطلاق بعضها من عامل الميناء ، بينما يستخدم الآخرون رمزًا برمجيًا جاهزًا جاهزًا ، ويتعين على المراجع نفسه أيضًا التعامل ليس مع زوجين ، ولكن مع عشرات العقود المبكرة مع إصدارات مختلفة من المترجم. لذلك ، يجب أن تكون قادرًا على " solc
" الإصدارات المختلفة من solc
مختلف ، سواء في النظام المضيف أو داخل صورة عامل solc
وداخل الكمأة ، لذلك سأعطيك خيارات الاختراق القليلة القذرة هذه:
1 طريقة: داخل الكمأة
لهذا ، ليست هناك حاجة الحيل ، ل بدءًا من إصدار truffle 5.0.0 ، يمكنك تحديد إصدار برنامج التحويل البرمجي مباشرةً في truffle.js ، كما هو الحال في هذا الفرق .
الآن سوف الكمأة تنزيل المترجم المطلوب وتشغيله. شكرًا جزيلاً للفريق على ذلك ، Solidity هي لغة شابة ، والتغييرات في اللغة خطيرة ، والانتقال من الإصدار إلى الإصدار غير مقبول للمراجع - وبهذه الطريقة يمكنك تقديم أخطاء جديدة وإخفاء الأخطاء القديمة.
الطريقة 2: استبدال / usr / bin / solc في حاوية عامل إرساء محلل
إذا تم توزيع المحلل في شكل Dockerfile ، فيمكنك استبداله عند تجميع صورة عامل ميناء بإضافة خط إلى Dockerfile يحصل على الإصدار المرغوب من solc
مباشرة من الصورة ، والذي يسحبه من الشبكة ويستبدل / usr / bin / solc:
COPY --from=ethereum/solc:0.4.19 /usr/bin/solc /usr/bin
3 طريقة: استبدال / usr / bin / solc
الطريقة الأقذر في الجبهة ، إذا لم يكن هناك مخرج على الإطلاق ، فيمكنك الاستعاضة عن / usr / bin / solc الثنائي بنص مثل هذا (لا تنس حفظ الملف الأصلي):
#!/bin/bash # run Solidity compiler of given version, pass all parameters # you can run “SOLC_DOCKER_VERSION=0.4.20 solc --version” SOLC_DOCKER_VERSION="${SOLC_DOCKER_VERSION:-0.4.24}" docker run \ --entrypoint "" \ --tmpfs /tmp \ -v $(pwd):/project \ -v $(pwd)/node_modules:/project/node_modules \ -w /project \ ethereum/solc:$SOLC_DOCKER_VERSION \ /usr/bin/solc \ "$@"
يقوم بتنزيل وتخزين صورة عامل ميناء مع الإصدار الصحيح من solc
، ويذهب إلى الدليل الحالي ويقوم بتشغيل /usr/bin/solc
مع المعلمات التي تم تمريرها. ليست طريقة جيدة للغاية ، ولكن ربما بالنسبة لك في بعض المهام سوف يناسبك.
كود التسوية
الآن دعونا معرفة المصدر. بطبيعة الحال ، من الناحية النظرية ، يجب على المحللون التلقائيون (خاصةً لتحليل المصدر الثابت) جمع العقد ، وسحب جميع التبعيات ، والجمع بين كل شيء في متراصة واحدة وتحليله. ولكن ، كما قلت سابقًا ، يمكن أن تكون التغييرات من إصدار إلى آخر خطيرة ، وقد تعثرت باستمرار على الحاجة لإسقاط دليل إضافي في عامل الإرساء ، وتكوينه داخل المسار ، وكل هذا حتى يسحب بشكل صحيح الواردات الضرورية. يفهم بعض المحللين كل شيء ، والثاني ليس ، بالتالي ، خيارًا عالميًا ، حتى لا يعانون من إلقاء أدلة إضافية ، فهو أكثر ملاءمة للمحللين الذين يتناولون ملفًا واحدًا لدمج كل شيء في ملف واحد وتحليله فقط.
للقيام بذلك ، استخدم مسطح الكمأة العادي .
هذه وحدة قياسية npm ، يتم استخدامها ببساطة شديدة:
truffle-flattener contracts/Booking.sol > contracts/flattened.sol
: https://github.com/trailofbits/slither
إذا كنت بحاجة إلى تخصيص طريقة التسوية بطريقة أو بأخرى ، فيمكنك كتابة التسوية الخاصة بك ، على سبيل المثال ، قبل استخدام الخيار القائم على الثعبان: https://github.com/mixbytes/solidity-flattener
لنبدأ التحليل.
على سبيل المثال نفس الرجل العجوز https://github.com/smartzplatform/constructor-eth-booking نواصل التحليل. يشير العقد إلى الإصدار القديم من المحول البرمجي "0.4.20" ، وأخذت عن قصد العقد القديم لحل مشاكل المحول البرمجي. يزداد الموقف سوءًا بسبب حقيقة أن أداة التحليل التلقائي ، على سبيل المثال ، دراسة الرمز الفرعي ، يمكن أن تعتمد على هذا الإصدار من solc ، وهنا يمكن للاختلافات في الإصدارات أن تؤثر بشكل كبير على النتائج أو حتى تحطيم كل شيء. لذلك حتى لو كنت تفعل كل شيء كوشير باستخدام أحدث الإصدارات ، لا يزال بإمكانك تشغيل محلل تم ضبطه على الإصدار السابق من المترجم.
تجميع وتشغيل الاختبارات
للبدء ، ما عليك سوى سحب المشروع من جيثب ومحاولة التجميع.:
git clone https://github.com/smartzplatform/constructor-eth-booking.git cd constructor-eth-booking npm install truffle compile
بالتأكيد لديك مشاكل مع إصدار برنامج التحويل البرمجي. أيضًا ، يواجه المحللون التلقائيون هذه المشكلات أيضًا ، لذلك استخدم أي وسيلة للحصول على برنامج التحويل البرمجي 0.4.20 وإنشاء المشروع. لقد سجلت الإصدار الضروري من المترجم في truffle.js وتم تجميع كل شيء كما هو موضح أعلاه.
أيضا تشغيل
truffle-flattener contracts/Booking.sol > contracts/flattened.sol
كما هو مبين في الفقرة حول التسوية ، فمن contracts/flattened.sol
سنقدم للتحليل لمختلف المحللين
خاتمة للمقدمة
الآن ، بعد أن أصبح flattened.sol والقدرة على استخدام solc
لنسخة عشوائية ، يمكنك البدء في التحليل. سوف أغفل مشاكل تشغيل الكمأة والاختبارات ، وهناك الكثير من الوثائق حول هذه المشكلة ، قم بتصنيفها بنفسك. بالطبع ، يجب تشغيل الاختبارات وتشغيلها بنجاح. أيضًا ، من أجل التحقق من المنطق ، يتعين على المراجع في كثير من الأحيان إضافة اختباراته الخاصة ، والتحقق من الأماكن التي يحتمل أن تتسرب منها ، على سبيل المثال ، التحقق من وظائف العقد على حدود المصفوفات ، مع تغطية جميع المتغيرات باختبارها ، حتى تلك المتوخاة بشكل صارم لتخزين البيانات ، إلخ. هناك العديد من التوصيات ، إلى جانب هذا هو المنتج الذي توفره شركتنا للسوق ، وبالتالي فإن دراسة المنطق مهمة إنسانية بحتة.
سوف نذهب إلى المحللين الذين يمثلون اهتمامًا من وجهة نظرنا ، وسنحاول إبرام عقدنا معهم ، وسنقدم نقاط الضعف فيه بشكل مصطنع من أجل تقييم كيفية تفاعل المحللون التلقائي معهم. سيتم تخصيص المقالة التالية لمحلل Slither ، وبشكل عام ، تكون خطة العمل كما يلي:
الجزء 1. مقدمة. تجميع ، تسطيح ، إصدارات من الصلابة (هذه المقالة)
الجزء 2. انزلق
الجزء 3. الأسطورة
الجزء 4. Manticore
الجزء الخامس
الجزء 6. أداة غير معروفة 1
الجزء 7. أداة غير معروفة 2
تم الحصول على هذه المجموعة من التحليلات لأنه من المهم للمراجع أن يكون قادرًا على استخدام أنواع مختلفة من التحليل - ثابتة وديناميكية ، وأنها تتطلب طرقًا مختلفة تمامًا. مهمتنا هي معرفة كيفية استخدام الأدوات الأساسية في كل نوع من أنواع التحليل وفهم الأدوات التي يجب استخدامها متى.
ربما في عملية دراسة تفصيلية ، سيظهر مرشحون جدد للنظر ، أو سيتغير ترتيب المقالات ، لذلك لا تنزعج. للانتقال إلى الجزء التالي ، "انقر هنا"