قراردادهای هوشمند، به‌ویژه آن‌هایی که در بستر بلاکچین‌هایی مانند Ethereum اجرا می‌شوند، به‌طور فزاینده‌ای در دنیای مالی و تجاری مورد استفاده قرار می‌گیرند. با این حال، امنیت این قراردادها به شدت حیاتی است، زیرا نقص‌های امنیتی می‌توانند منجر به از بین رفتن دارایی‌ها و اطلاعات شوند. یکی از تهدیدات رایج، حمله Reentrancy است. در این مقاله به بررسی این نوع حمله و راهکارهای جلوگیری از حملات Reentrancy و دیگر تهدیدات امنیتی خواهیم پرداخت.

حمله Reentrancy چیست؟

حمله Reentrancy یک نوع حمله است که در آن یک قرارداد هوشمند، قبل از اینکه وضعیت خود را به‌روزرسانی کند، یک تماس به قرارداد دیگری ارسال می‌کند. این مشکل می‌تواند به مجرمان این امکان را بدهد که چندین بار به یک تابع دسترسی پیدا کنند و به‌طور غیرمجاز دارایی‌ها را برداشت کنند.

نمونه‌ای از حمله

فرض کنید که یک قرارداد هوشمند کیف پول، عمل برداشت را به‌صورت زیر پیاده‌سازی کرده باشد:

function withdraw(uint _amount) public {
    require(balances[msg.sender] >= _amount);
    msg.sender.call.value(_amount)(""); // انتقال ETH به کاربر
    balances[msg.sender] -= _amount; // به‌روزرساني بعد از انتقال
}

در این کد، اول پول به کاربر ارسال می‌شود و سپس موجودی او کاهش می‌یابد. اگر کاربری قرارداد دیگری را ایجاد کند که در آن توابعی برای ورود به سیستم و مجدداً تماس با تابع برداشت وجود داشته باشد، می‌تواند به‌طور مکرر از موجودی برداشت کند.

جلوگیری از حملات Reentrancy

برای جلوگیری از حملات Reentrancy، می‌توان از یکی از روش‌های زیر استفاده کرد:

  1. استفاده از الگوی Checks-Effects-Interactions: وضعیت قرارداد باید ابتدا بررسی و به‌روزرسانی شود قبل از اینکه تماس به یک قرارداد دیگر انجام شود.
function withdraw(uint _amount) public {
    require(balances[msg.sender] >= _amount);
    balances[msg.sender] -= _amount; // به‌روزرساني
    msg.sender.transfer(_amount); // انتقال ETH
}
  1. استفاده از Mutex: می‌توان یک قفل (mutex) برای جلوگیری از اجرای هم‌زمان یک تابع خاص مورد استفاده قرار داد.
bool private locked;

modifier noReentrancy() {
    require(!locked, "No reentrancy");
    locked = true;
    _;
    locked = false;
}

function withdraw(uint _amount) public noReentrancy {
    // عمل برداشت
}

آموزش سالدیتی + 5 پروژه عملی

دیگر تهدیدات امنیتی

علاوه بر حمله Reentrancy، قراردادهای هوشمند می‌توانند تحت تأثیر تهدیدات دیگری نیز قرار گیرند:

  1. حملات دستکاری دوباره (Front-Running): این نوع حمله زمانی رخ می‌دهد که یک مجرم، تراکنش‌های دیگر را قبل از پردازش آن‌ها اجرا کند تا به نفع خود سود ببرد. برای جلوگیری از این حمله می‌توان از تکنیک‌های مختلفی مانند استفاده از gas price و حاشیه زمان (timing) مناسب استفاده کرد.
  2. حملات Overflow و Underflow: این نوع حملات زمانی رخ می‌دهد که مقادیر عددی به صورت غیرمنتظره کاهش یا افزایش یابند. برای جلوگیری از این نوع حملات، می‌توان از کتابخانه SafeMath در Solidity استفاده کرد.
using SafeMath for uint;

function exampleFunction(uint _value) public {
    uint result = _value.add(10); // جلوگیری از overflow
}
  1. عدم مدیریت مناسب مجوزها: برخی از قراردادها، اگر مجوزها به درستی تنظیم نشوند، می‌توانند به مهاجمین اجازه دهند که به توابع حساس دسترسی پیدا کنند. برای جلوگیری از این مشکل، استفاده از کنترل‌های مجوز قوی و Audit کدها ضروری است.

نتیجه‌ گیری

امنیت قراردادهای هوشمند یک موضوع پیچیده اما حیاتی است. با استفاده از الگوهای مناسب برنامه‌نویسی و احتیاط در طراحی، می‌توان از بروز حملات مختلف، جلوگیری از حملات Reentrancy را انجام داد. با رشد این فناوری، آشنایی با تهدیدات و بهترین شیوه‌های امنیتی باید در اولویت قرار گیرد تا از محافظت بهینه از دارایی‌ها و اطلاعات کاربران اطمینان حاصل شود.