Solidity الهجمات و الثغرات

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

خلال الأقسام القليلة التالية ، سنناقش أمان العقد الذكي. سنبدأ من خلال تجاوز بعض المخاطر والهجمات الشائعة باستخدام Solidity (كلغة) والعقود الذكية بشكل عام. .

نصائح Solidity 

استخدام إصدار محدد لـ Compiler

من الطرق الشائعة استخدام ^ للإشارة إلى أقل إصدار من Compiler سيعمل معه عقدك. ومع ذلك ، إذا كان لديك مجموعة اختبار قمت بإنشائها وفقًا لعقدك ، فلا يجب عليك تضمين ^ وإدراج إصدار Compiler فقط.

          pragma solidity ^0.4.4; // Possibly dangerous
          pragma solidity 0.4.4; // Better

أسماء المتغيرات المضمنة

يمكن تظليل (shadowed) المتغيرات المضمنة ، كن حذرًا عند تسمية وظائفك:

function revert() internal pure {} // Possibly dangerous
function myRevert() internal pure {} // Better    

الاستخدام السليم require و assert و revert

require(msg.sender == owner)

  • التحقق من صحة المدخلات وإرجاع المكالمات الخارجية والمتغيرات قبل تغيير الحالة
  • إرجاع مبالغ الغاز المتبقي عند الفشل
  • يجب استخدامه في كثير من الأحيان وفي بداية الوظائف

assert(age > 100)

  • التحقق من صحة الثوابت ، والمواقف التي لا ينبغي أن تحدث أبدًا والمتغيرات بعد تغير الحالة
  • يستهلك كل الغاز عند الفشل
  • يجب استخدامه بشكل أقل و في نهاية الوظائف

revert()

  • إرجاع المعاملة الحالية لحالتها الأصليه 
  • إرجاع مبالغ الغاز المتبقي عند الفشل
  • تستخدم ضمن عبارات if-else

استخدم المعدلات فقط لعمليات التحقق من الصحة

ما عليك سوى إجراء عمليات التحقق من الصحة داخل المُعدِّلات وتجنب المكالمات الخارجية عليها:

modifier partnerShare() {        // Possibly dangerous
partner.transfer(msg.value / 10); _; }
modifier onlyOwner() {             // Better!
require(msg.sender == owner); _; }
          

السحب أفضل من الدفع 

إعطاء الأولوية لتلقي مكالمات العقد على إجراء مكالمات العقد:

function doRefund() external onlyOwner {      // Possibly dangerous
  uint refund;
  for(uint i = 0; i < refunds.length; i++) {
      refund = refunds[i].value;
      refunds[i].value = 0;
      refunds[i].addr.transfer(refund);
  }
}          
 
function withdrawRefund() external {      // Better!
  require(refunds[msg.sender] > 0);
  uint refund = refunds[msg.sender];
  refunds[msg.sender] = 0;
  msg.sender.transfer(refund);
}
      

وظائف Fallback وطول البيانات

اجعل الوظائف Fallback بسيطة وتحقق من طول البيانات:

fallback() payable external {   // Possibly dangerous
  balances[msg.sender] += msg.value;
}  
     
receive() external {           // Better!
  balances[msg.sender] += msg.value;
}
fallback() external {
  require(msg.data.length == 0);
  emit LogDeposit(msg.sender);
}

تحقق من التاثيرات الناتجة من التفاعلات

تجنب تغييرات الحالة بعد المكالمات الخارجية ، لتجنب أشياء مثل the DAO hack:

function withdraw(uint amount) public {       // Possibly dangerous
  require(balances[msg.sender] >= amount);
  msg.sender.call.value(amount)("");
  balances[msg.sender] -= amount;
}
function withdraw(uint amount) public {    // Better!
  require(balances[msg.sender] >= amount);
  balances[msg.sender] -= amount;
  msg.sender.call.value(amount)("");
}
   

الاستخدام السليم call ، delegatecall  بدلاً من send، transfer

بعد تشعب إسطنبول الصلب ، يوصى بعدم استخدام send و transfer ، وبدلاً من ذلك استخدام call.value

contract Vulnerable {         // Possibly dangerous
  function withdraw(uint256 amount) external {
      // This forwards 2300 gas, which may not be enough if the recipient
      // is a contract and gas costs change.
      msg.sender.transfer(amount);
  }
}
   
contract Fixed {            // Better!
  function withdraw(uint256 amount) external {
      // This forwards all available gas. Be sure to check the return value!
      (bool success, ) = msg.sender.call.value(amount)("");
      require(success, "Transfer failed.");
  }
}
     

ثم الاستخدام السليم call و delegatecall:

addr.call(abi.encodeWithSignature("f(uint)", a));
  • تستخدم لاستدعاء الوظائف وإرسال الأثير
  • يسمح بتحديد الغاز
  • إرجاع قيمة منطقية
  • لا ينشر الاستثناءات
addr.delegatecall(abi.encodeWithSignature("f(uint)", a));
  • تُستخدم لتشغيل الوظائف ضمن سياق المتصل (ميزة المكتبة)
  • يسمح بتحديد الغاز
  • إرجاع قيمة منطقية
  • لا ينشر الاستثناءات

مواد اضافية

إضافة تعليق