قرارداد هوشمند چیست؟
دو نوع حساب رایج اتریوم شامل حسابهای تحت مالکیت خارجی (EOA) و حسابهای قرارداد هوشمند (SCA) هستند.
حساب EOA بسیار شبیه به حسابهای مالی الکترونیکی است و از آن معمولاً برای ذخیره وجوه و تعامل با اپلیکیشنها استفاده میکنیم. برای مثال، کاربران ارز فیات را از طریق پیپال (PayPal) واریز میکنند و سپس از این وجوه برای پرداخت در وبسایتها، فروشگاهها و اپلیکیشنهای مختلف استفاده میکنند. ماینرهای دیفای (DeFi) معمولاً کریپتوها را در حساب EOA خود ذخیره میکنند، از طریق اپلیکیشنهای غیرمتمرکز (dAppها) تعامل میکنند، و وجوهی را برای کسب سود به اپلیکیشنهای غیرمتمرکز واریز میکنند. با این حال، حساب EOA ویژگیای دارد که حسابهای مالی الکترونیکی فاقد آن هستند بهطوریکه، کاربران برای کنترل بر حساب EOA خود باید به کلیدهای خصوصی این حسابها دسترسی داشته باشند. بهعبارتدیگر، عدم دسترسی به این کلیدها به معنای عدم دسترسی به کوینهایتان است.
حساب SCA اساساً با بخشی از بایتکد قابلاجرا، که با عنوان قرارداد هوشمند نیز شناخته میشود، مرتبط است. قرارداد هوشمند توصیفکننده منطقهای تجاری مختلف و همچون پشتوانهای برای اپلیکیشنهای غیرمتمرکز است. اگرچه قراردادهای هوشمند شبهتورینگکامل محدودیتهای بیشتری در مقایسه با زبانهای توسعه تورینگکامل سنتی دارند، در برابر حملات متعددی آسیبپذیرند و ضربات بیشماری را به صنعت بلاکچین وارد میکنند.
حملات متداول علیه قراردادهای هوشمند
1. حمله ورود مجدد
حمله ورود مجدد (Reentrancy Attack) متداولترین و بدنامترین نوع حمله است که موجب فورک اتریوم و ایجاد اتریوم کلاسیک شد. هکرها، در سال 2016، حمله ورود مجددی به قرارداد The DAO انجام دادند و 3,600,000 رمزارز اتریوم را به ارزش بیش از 150 میلیون دلار سرقت کردند. این حمله که در مراحل اولیه تکامل بلاکچین اتریوم رخ داد، اکوسیستم اتریوم و اعتماد سرمایهگذاران را از بین برد و درنهایت از طریق اجرای فورک اتریوم با آن مقابله شد.
منطق خاص
در ادامه، مثالی برای فهم بهتر سازوکار حمله ورود مجدد ارائه شده است. بانک B قبلاً مقداری پول به بانک A قرض داده است. روزی بانک B حوالهای را به بانک A ارسال میکند تا کل پول را به بانک B بازگرداند. مسیر عادی انجام این انتقال به شرح زیر است:
مرحله 1: بانک B درخواست برداشت وجه را ارسال میکند.
مرحله 2: بانک A وجوه را به بانک B منتقل میکند.
مرحله 3: بانک A انتقال موفق وجوه به بانک B را تأیید میکند.
مرحله 4: بانک A موجودی حساب بانک B را بهروزرسانی میکند.
حال اگر بانک B بعد از مرحله 2 حفرهای ایجاد کند و پس از درخواست کل پولش از بانک A، دریافت این پول را تأیید (مرحله 3) را تائید نکند، موجودی حساب بانک A در بانک B تغییری نخواهد کرد. با انجام بازگشتی این فرآیند، کل داراییهای بانک A را میتوان برداشت کرد.
قراردادهای هوشمند مرتبط
قرارداد بانک A شامل دو تابع زیر است:
- ()deposit: تابع واریزی که پول را به بانک A واریز میکند و موجودی کاربر را بهروزرسانی میکند.
- ()withdraw: تابع برداشتی که کاربران با استفاده از آن میتوانند تمام وجوهشان را از بانک A برداشت کنند.
قرارداد حمله بانک B عمدتاً شامل حلقهای است که تابع receive() را فراخوانی میکند. تابع receive() نیز، بهنوبه خود، تابع remove() قرارداد بانک را برای تخلیه داراییهای بانک A از طریق دنبالهای از 1 سپرده، 1 برداشت، و فراخوانی تابع کالبک (callback) receive()، و درنهایت، بهروزرسانی موجودی بانک B در بانک A، فراخوانی میکند. این فرآیند شامل دو تابع زیر است:
- ()receive: اجرای تابع کالبک پس از دریافت اتریوم آغاز میگردد و بهصورت بازگشتی تابع ()withdraw قرارداد بانک را برای انجام برداشت فراخوانی میکند.
- ()attack: این تابع ابتدا تابع ()deposit قرارداد بانک را فراخوانی میکند تا موجودی حساب را بهروزرسانی کند و سپس تابع کالبک ()withdraw را برای شروع اولین برداشت فراخوانی میکند. سپس، تابع کالبک ()receive را برای فراخوانی بازگشتی تابع ()withdraw برای تخلیه داراییهای قرارداد بانک فراخوانی میکند.
راهحل
اجرای قفل ورود مجدد
قفل ورود مجدد روشی اصلاحی برای جلوگیری از ورود مجدد است که تضمین میکند هر فراخوانی قبل از فراخوانی مجدد باید بهطور کامل اجرا شود. برای مثال، چون حمله توسط بانک B مستلزم چند بار فراخوانی کردن تابع ()remove قرارداد بانک است، در صورت اجرای قفل ورود مجدد، بانک دیگر نمیتواند در دفعات بعدی برداشتی انجام دهد.
نحوه استفاده از آن
2. سوءاستفاده از tx.origin
عملکرد اصلی tx.origin در قراردادهای هوشمند، بازیابی حساب اصلیای است که تراکنش را آغاز کرده است. در ادامه، درباره دو متغیر رایج در قراردادهای هوشمند صحبت خواهیم کرد: تابع msg.sender، و تابع tx.origin. تابع msg.sender حسابی را که مستقیماً قرارداد هوشمند را فراخوانی کرده است، بازیابی میکند. تابع tx.origin نیز، در دنیای بلاکچین، به دلیل فراخوانیهای تودرتو و متقابل قراردادهای هوشمند مختلف (مانند DeFi Lego)، برای تشخیص حساب اصلی شروعکننده تراکنشها موردنیاز است. یک آسیبپذیری دیگر زمانی رخ میدهد که توسعهدهندگان اپلیکیشنهای غیرمتمرکز فقط امنیت tx.origin را در کد مربوطه تأیید میکنند، و از تأیید امنیت مهاجمانی که از قراردادهای میانی برای دور زدن tx.origin و اجرای حملات استفاده میکنند، غفلت میکنند.
منطق خاص
در ادامه، مثالی برای فهم عمیق این سناریوی حمله رایج ارائه شده است. کیف پول هوشمند بیل تأیید میکند که آیا او آغازگر انتقال بوده است یا خیر. وقتی بیل یک NFT روی وبسایتی فیشینگ ایجاد کرد، وبسایت توانست هویتش را تشخیص دهد و با سوءاستفاده از اطلاعات هویتش، توانست انتقالی را از کیف پول هوشمندش اجرا و داراییهایش را سرقت کند. در حالت عادی، کاربران کمتر در دام این تله میافتند، ولی هنگام تعامل با اپلیکیشنهای غیرمتمرکز و استفاده از کیف پول، اغلب فراموش میکنند که اعلانهای تعاملی را بررسی کنند. برای مثال، اگر هم اپلیکیشن و هم تابع حاوی تابع ()Mint باشند، کاربران بیدقت ممکن است بهراحتی در دام فیشینگ بیفتند. منطق کسبوکار در وبسایتهای فیشینگ حاوی تلههای متعددی است. بنابراین، بررسی پیامهای تعاملی برای تشخیص وجود خطا در طول تعاملات منظم اهمیت زیادی دارد.
قرارداد کیف پول هوشمند
قرارداد کیف پول هوشمند شامل یک تابع زیر است:
- ()transfer: تابع برداشتی که فقط توسط مالک کیف پول، که در این مثال بیل است، قابلاجرا است.
قرارداد حمله فیشینگ
تابع ()Mint در یک قرارداد حمله فیشینگ، باعث میشود کاربران وجوهشان را به آدرس هکر منتقل کنند. این قرارداد از تابع زیر استفاده میکند:
- ()Mint: این تابع فیشینگ، پس از فراخوانی، در داخل خود تابع ()transfer قرارداد Wallet را اجرا میکند. چون آغازگر اصلی این تابع خود کاربر (در این مثال، بیل) است، تأیید require (tx.origin == owner, "Not owner") مشکلساز نخواهد بود. با این حال، آدرس موردنظر برای انتقال قبلاً دستکاری شده است و بهبه آدرس هکر تغییر یافته است تا امکان سرقت از صندوق فراهم شود.
راهحلها
1. استفاده از msg.sender بهجای tx.origin
مهم نیست که چه تعداد قرارداد درگیر شده باشند (قرارداد A ← قرارداد B ←… ← قرارداد هدف)، کافی است فقط تابع msg.sender را تأیید کنید تا مانع از حملات ناشی از قراردادهای واسطهای مخرب شوید.
2. تأیید برابری tx.origin == msg.sender
با این روش میتوان از اجرای قراردادهای مخرب ممانعت کرد، ولی توسعهدهندگان باید واقعیتهای تجاریشان را در نظر بگیرند، زیرا این واقعیتها همه فراخوانیهای قرارداد خارجی دیگر را بهنحوی مؤثر از یکدیگر جدا کنند.
3. حمله تولید اعداد تصادفی (RNG)
داستان این حمله به روند قمار یا شرطبندی از طریق اپلیکیشنهای غیرمتمرکز در حدود سالهای 2018 و 2019 برمیگردد. در حالت معمول، توسعهدهندگان از سیدهای خاصی در قراردادهای هوشمند برای تولید اعداد تصادفی برای انتخاب برندگان قرعهکشیها استفاده میکنند. سیدهای رایج عبارتاند از: block.number، block.timestamp، blockhash و keccak256. با این حال، ماینرها میتوانند بهطور کامل این سیدها را کنترل کنند. بنابراین، در برخی موارد، ماینرهای مخرب ممکن است متغیرها را برای بهرهمندی از مزایا دستکاری کنند.
قراردادهای دایس مشترک
قرارداد دایس (Dice) شامل تابع زیر است:
- ()Bet: تابعی شرطبندی است که در آن کاربران عددی شرطبندی را وارد و یک اتریوم پرداخت میکنند. عددی تصادفی با چند سید تولید میشود، و اگر عدد شرطبندی و عدد تصادفی مطابقت داشته باشد، کاربر کل جایزه را برنده میشود.
قرارداد حمله ماینر
ماینرها مادامیکه بتوانند عدد تصادفی برنده را از قبل محاسبه و در بلوکی یکسان اجرا کنند، میتوانند برنده شوند. این قرارداد شامل تابع زیر است:
- ()attack: یک تابع حمله شرطبندی است که در آن، ماینر عدد تصادفی برنده را از قبل محاسبه میکند. چون این تابع در بلوکی یکسان اجرا میشود، دو تابع blockhash(block.number - 1) و block.timestamp واقع در بلوکی یکسان مشابه هستند. سپس، این ماینر تابع ()Bet قرارداد دایس را برای تکمیل حمله فراخوانی میکند.
راهحل
از اعداد تصادفی برونزنجیرهای ارائه شده توسط پروژههای اوراکل استفاده کنید
اعداد تصادفی درونزنجیرهای با استفاده از خدمات ارائه شده توسط پروژههای اوراکل، مثل چینلینک (Chainlink)، به درون قراردادهای درونزنجیره ای وارد میشوند تا تصادفیبودن و امنیت تضمین گردد. با این حال، پروژههای اوراکل مرتبط با ریسکهای متمرکزسازی نیز هستند؛ بنابراین، به خدمات اوراکل بالغتری نیز نیاز است.
4. حمله اجرای مجدد
حمله اجرای مجدد شامل شروع مجدد یک تراکنش با استفاده از امضای استفادهشده قبلی برای سرقت وجوه است. یکی از شناختهشدهترین حملات اجرای مجدد، در سالهای اخیر، سرقت 20 میلیون توکن $OP از بازارساز وینترمیوت (Wintermute) در اکوسیستم آپتیمیسم (Optimism) بود، که در قالب یک حمله اجرای مجدد میانزنجیرهای اجرا شده بود. چون حساب کیف پول چندامضایی وینترمیوت موقتاً فقط در شبکه اصلی اتریوم مستقر شده بود، فرد هکر از امضای تراکنش برای استقرار وینترمیوت یک آدرس چندامضایی روی اتریوم برای اجرای مجدد همان تراکنش در زنجیره آپتیمیسم استفاده کرد تا بتواند کنترل حساب کیف پول چند امضایی را در آپتیمیسم به دست آورد. یک حساب کیف پول چند امضایی اساساً یک حساب قرارداد هوشمند است که موجب ایجاد تفاوت قابلتوجهی بین حسابهای SCA و EOA نیز میشود. در حسابهای EOA، کاربران معمولی برای کنترل تمام آدرسهای موجود در زنجیره اتریوم و زنجیرههای سازگار با EVM فقط به کلیدی خصوصی نیاز دارند (رشتههای آدرس دقیقاً یکسان هستند)، درحالیکه حسابهای SCA فقط پس از تنها روی زنجیره مؤثر هستند.
منطق خاص
در ادامه، مقالی از حمله اجرای مجدد معمولی (حمله اجرای مجدد روی زنجیرهای یکسان) ارائه کردهایم. کیف پول هوشمند بیل مستلزم آن است که قبل از انجام هر تراکنش، امضای الکترونیکیاش را وارد کند. حال که هکری به نام لوسی امضای الکترونیکی بیل را دزدیده است، میتواند تعداد نامحدودی تراکنش را برای تخلیه کیف پول هوشمند بیل اجرا کند.
مثال
قراردادهای مستعد آسیبپذیری شامل سه نوع تابع هستند:
- ()checkSig: تابع تأیید ECDSA تضمین میکند که نتیجه تأیید توسط امضاکننده اصلی تنظیم شده است.
- ()getMsgHash: تابعی برای تولید هش است که با هش ترکیب میشود و مقدار هش را ایجاد میکند.
- ()transfer: کاربران با استفاده از تابع انتقال میتوانند وجوهشان را از استخر نقدینگی برداشت کنند. به دلیل عدم محدودیت در امضا، میتوان از امضایی یکسان مجدداً استفاده کرد و در نتیجه، هکرها میتوانند به طور مداوم وجوه افراد را سرقت کنند.
راهحل
برای جلوگیری از حملات اجرای مجدد، نانس (nonce) را در ترکیب امضا قرار دهید. اصل پارامتر به شرح زیر است:
- نانس: نانس متغیر تعداد تراکنشهای یک حساب EOA را در شبکه ای بلاکچین توصیف میکند. نانس منظم و منحصربهفرد دارد. مقدار نانس پس از هر تراکنش اضافی، یک واحد افزایش مییابد. شبکه بلاکچین بررسی میکند که آیا نانس این معامله با نانس جاری این حساب مطابقت دارد یا خیر. بنابراین، اگر هکری از امضایی استفادهشده مجدداً استفاده کند، شکست میخورد، زیرا مقدار نانس این ترکیب امضا کمتر از مقدار نانس فعلی حساب EOA است.
5. حمله محرومیت از سرویس (DoS)
حمله محرومیت از سرویس (DoS) در دنیای سنتی وب2 چیز جدیدی نیست. این حملات به هرگونه اختلال در کار یک سرور، مثل ارسال حجم زیادی از اطلاعات ناخواسته یا مخرب و مختل کردن یا از بین بردن کامل در دسترس بودن اشاره دارد. مشابها، قراردادهای هوشمند نیز با چنین حملاتی، که اساساً هدفشان از کار انداختن قراردادهای هوشمند است، مواجه میشوند.
منطق خاص
بیایید مثالی را بررسی کنیم. پروژه A در حال عرضه عمومی توکن پروتکلش است. در این عرضه عمومی، همه کاربران میتوانند وجوهی را به استخر نقدینگی (قرارداد هوشمند) برای خرید سهمیهها واریز کنند (با این شرط که کاربرانی که در صف جلوتر هستند باید زودتر خدمات بگیرند، و وجوه اضافی به شرکتکنندگان بازگردانده میشود). هکری به نام آلیس از قرارداد حمله برای شرکت در عرضه عمومی سوءاستفاده میکند. وقتی استخر نقدینگی سعی دارد وجوهی را به قرارداد حمله آلیس برگرداند، یک حمله DoS آغاز میشود و مانع از تحقق عمل بازگشت میشود. در نتیجه، مقدار زیادی از وجوه در قراردادهای هوشمند قفل خواهند شد.
مثال
قرارداد عرضه عمومی شامل دو تابع زیر است
- ()depozit: یک تابع واریز است که آدرس واریزکننده و مبلغ مربوطه را ثبت میکند.
- ()refund: تابع بازپرداختی است که با آن تیم پروژه وجوهی را به سرمایهگذاران بازمیگرداند.
قرارداد حمله DoS
قرارداد حمله DoS شامل تابع زیر است:
- ()attack: اگرچه یک تابع حمله است، ولی استفاده از آن هیچ مشکلی ندارد. مشکل اصلی در تابع کالبک پرداخت ()receive است که در قرارداد Hacker، که شامل قضاوتی درباره استثناها است، تعبیه شده است. هر قرارداد خارجی، که وجوهی را به قرارداد Hacker منتقل میکند، استثنایی را از طریق ()revert ایجاد میکند که در نتیجه آن، از تکمیل عملیات جلوگیری میشود.
راهحلها
1. از گیرکردن کارکردهای حیاتی حین ایجاد قراردادهای خارجی اجتناب کنید
تابع require (success, "Refund Fail!") را از تابع ()refund قرارداد PublicSale فوق حذف کنید تا تداوم عملیات بازپرداخت (حتی اگر بازپرداخت به آدرسی واحد با شکست مواجه شود) تضمین گردد.
2. جداسازی
کاربران در تابع ()refund قرارداد PublicSale فوق، بهجای توزیع وجوهشان، میتوانند با وجوه خودشان بازپرداخت را انجام دهند، که در نتیجه، تعاملات غیرضروری با قراردادهای خارجی کمینه میگردد.
6. حمله پرمیت
در حمله پرمیت، حساب A از قبل امضای طرف دیگر را فراهم میکند و سپس حساب B، پس از دریافت این امضا، مجاز انتقال توکن را برای سرقت مقدار معینی از توکن ها خواهد داشت. در ادامه، ابتدا درباره دو تابع رایج (یعنی ()approve و ()permit) برای بررسی مجازبودن توکن در قراردادهای هوشمند توضیح میدهیم.
در قرارداد مشترک ERC20، حساب A میتواند با فراخوانی ()approve، انتقال مقدار معینی از توکنها را به حساب B مجاز کند، و در ادامه، حساب B میتواند آن توکنها را از حساب A منتقل کند. بعلاوه، استفاده از تابع ()permit در قراردادهای ERC20 در EIP-2612 ممکن شد و یونیسوآپ (Uniswap) استاندارد مجوز جدید توکن را، به نام Permit2، در نوامبر 2022 منتشر کرد.
منطق خاص
در ادامه مثالی ارائه شده است. روزی بیل در حال مرور یک وب سایت خبری بلاکچین بود که ناگهان یک پنجره پاپآپ امضای متامسک در مقابل دیدگانش ظاهر شد. چون بسیاری از وبسایتها یا برنامههای بلاکچین از امضا برای تأیید ورود کاربران استفاده میکنند، بیل خیلی به آن توجه نکرد و مستقیماً امضا را تکمیل کرد. پنج دقیقه بعد، داراییهای کیف متامسکش تخلیه شد. سپس بیل در مرورگر بلاکچینش متوجه شد که آدرسی ناشناخته ابتدا یک تراکنش ()permit و سپس یک تراکنش ()transferFrom را اجرا و کیف پولش را خالی کرده است.
مثال
تعریف دو تابع فوق به شرح زیر است:
- ()approve: یک تابع مجوز استاندارد است که مقدار وجوه مشخصی را از حساب A به حساب B منتقل میکند.
- ()permit: یک تابع مجوز امضا است که در آن، حساب B تأیید امضا را تکمیل و ارسال میکند تا مبلغ مجازی را از حساب A دریافت کند. این پارامترها شامل اعطای مجوز توسط مالک، تأیید مجوز توسط مصرفکننده، مبلغ مجاز، مهلت زمانی امضا، و دادههای امضای مالک v، r و s است.
راهحلها
1. به هر امضا در تعاملات درونزنجیرهای توجه کنید
بهرغم اقداماتی که برخی کیف پولها برای رمزگشایی و نمایش اطلاعات امضای مجوز ()approve انجام میدهند، تقریباً هیچ هشداری برای فیشینگ امضای ()permit ارائه نمیدهند و در نتیجه، ریسک حملات افزایش مییابد. بنابراین، اکیداً توصیه میشود که هر امضای ناشناختهای را بهدقت بررسی کنید تا مطمئن شوید که آیا هدف این امضا تابع ()permit است یا خیر.
2. کیف پول موردنظر برای تعامل منظم را از کیف پول ذخیرهسازی داراییها جدا کنید
این جداسازی برای کاربران کریپتو، و بهویژه شکارچیان ایردراپ، بسیار مهم است، زیرا هر روز با تعداد بیشماری اپلیکیشن یا وبسایت غیرمتمرکز تعامل دارند و مستعد ایجاد تله هستند. ذخیره مقدار کمی از وجوه در کیف پول برای تعامل منظم میتواند ضرر احتمالی مدیریت کند.
7. حمله هانیپات
حمله هانیپات، در صنعت بلاکچین، نوعی قراردادهای توکن مخرب مستقرشده توسط تیمهای پروژه هستند. این قرارداد فقط به تیمهای پروژه اجازه فروش را میدهد، ولی کاربران معمولی فقط میتوانند بهجای فروش خرید کنند و در نتیجه، متحمل ضرر میشوند.
منطق خاص
به این مثال توجه کنید. پروژه A طی اطلاعیهای در تلگرام به کاربران اطلاع میدهد که این توکن در شبکه اصلی مستقر شده و برای معامله در دسترس است. چون این توکن فقط قابلخرید است و نمیتوان آن را فروخت، قیمت در ابتدا افزایش پیدا میکند و کاربرانی که ترس از دست دادنش را دارند به خریدش ادامه میدهند. پس از مدتی کاربران متوجه میشوند که قادر به فروش این توکن نیستند، تیم پروژه از فرصت استفاده میکند و توکنهایش را برای فروش منتشر میکند و موجب کاهش شدید قیمت این توکن میشود.
مثال
تابع اصلی:
- تابع _ beforeTokenTransfer(): تابعی داخلی است که طی انتقال توکن فراخوانی میشود، و اجرای آن فقط زمانی موفق میشود که توسط مالک فراخوانی شود؛ فراخوانی این تابع توسط سایر حسابها با شکست مواجه خواهد شد.
راهحل
از ابزارهای اسکن امنیتی استفاده کنید:
- ابزار Token Sniffer برای توکن های اتریوم
- ابزار Ave Check برای توکنهای روی سایر زنجیرهها
- وبسایتها بازار با ابزارهای تشخیص داخلی مثل Dextools
از معامله توکن های دارای امتیاز پایین اجتناب کنید.
8. حمله فرانت-رانینگ (Front-Running)
این نوع حمله ابتدا در بازارهای مالی سنتی ظاهر شد. در این بازارها، واسطههای مالی از طریق عدم تقارن اطلاعاتی و با انجام اقداماتی سریع میتوانند بر اساس اطلاعات خاص صنعت، سود کسب کنند. در صنعت بلاکچین، حملات فرانت-رانینگ عمدتاً ناشی از فرانت-رانینگ درونزنجیرهای هستند. این حملات شامل دستکاری ماینرها برای افزایش اولویت تراکنشهایشان در زنجیره برای کسب سود است.
ماینرها در حوزه بلاکچین میتوانند با دستکاری تراکنشهایی که در قالب بلاکها بستهبندی میکنند، سود کسب کنند (برای مثال، مستثنا ساختن برخی تراکنشهای خاص و آرایش مجدد تراکنشها). چنین سودی را میتوان با تابع Miner Extractable Value (MEV) اندازهگیری کرد. قبل از اینکه تراکنش کاربر به شبکه اصلی اتریوم اضافه شود، اکثر تراکنشها در ممپول (mempool) جمع میشوند. ماینرها معاملاتی با قیمت گس بالاتر را در این مجموعه جستجو میکنند و برای بیشینهکردن سودشان، اولویت پکشان را افزایش میدهند. بهطورکلی، معاملات با قیمت گس بالاتر توسط ماینرها راحتتر انجام میشود. در همین حال، برخی رباتهای MEV نیز ممپول را برای یافتن تراکنشهای سودآور جستجو میکنند.
منطق خاص
به این مثال توجه کنید. بیل توکن داغ جدیدی با نوسانات قیمت قابلتوجه را کشف میکند. بیل، برای اطمینان از موفقیت تراکنشهای این توکن در یونیسوآپ، محدوده لغزش وسیعی را تعیین میکند. متأسفانه، ربات MEV آلیس این تراکنش را در ممپول شناسایی میکند و بهسرعت کارمزد گس را افزایش میدهد. در نتیجه، معامله خریدی قبل از بیل آغاز میشود و معامله فروشی بعد از معامله بیل در همان بلوک درج میشود. تأیید بلوک منجر به ضرر قابلتوجه بیل در اثر لغزش قیمت میشود، و در مقابل، آلیس از عملیات آربیتراژ خرید در قیمت پایین و فروش در قیمت بالا سود میبرد.
مثال
این تابع به صورت زیر است:
- solve(): تابعی برای حدسزدن است. هر کسی میتواند پاسخی را ارسال کند، و اگر پاسخ ارسالی با پاسخ هدف مطابقت داشته باشد، ارسالکننده میتواند 10 اتر دریافت کند.
فرآیند:
- بیل پاسخ صحیح را پیدا میکند.
- آلیس ممپول را زیر نظر دارد و منتظر است تا کسی پاسخ صحیح را ارسال کند.
- بیل برای ارسال پاسخ تابع ()solve را فرامیخواند و قیمت گس را برابر با 100 گیوی (Gwei) تعیین میکند.
- آلیس تراکنش ارسال شده توسط بیل را میبیند و پاسخ را کشف میکند. او قیمت گسی بالاتر از 200 گیوی بیل تعیین میکند و تابع ()solve را فرامیخواند.
- معامله آلیس توسط ماینر قبل از بیل بستهبندی میشود.
- آلیس برنده جایزه 10 اتر میشود.
راهحل
سه تابع اصلی به شرح زیر هستند:
- ()commitSolution: تابعی برای ارسال نتایج، قرار دادن پاسخ ارسالی کاربر solutionHash، زمان ارسال commitTime، و وضعیت آشکار شده در ساختار Commit است.
- ()getMySolution: تابعی برای به دست آوردن نتایج است. کاربران از طریق این تابع میتوانند پاسخهای ارسالی و اطلاعات مرتبطشان (از جمله پاسخ ارسالی کاربر SolutionHash، زمان ارسال commitTime و وضعیت revealed) را مشاهده کنند.
- ()discoverSolution: تابعی برای درخواست پاداش حدس زدن جواب پازل است. کاربران از طریق این تابع میتوانند پس از ارائه پاسخ و رمز عبوری که تعیین کردهاند، پاداش دریافت کنند.
فرآیند:
- بیل پاسخ صحیح را پیدا میکند.
- بیل تابع ()commitSolution را برای ارسال پاسخ صحیح فرامیخواند.
- در بلوک بعدی، بیل با ارائه پاسخ و رمز عبوری که برای مطالبه پاداش تعیین کرده است، تابع commitSolution() را فراخوانی میکند.
بیل از طریق تابع ()commitSolution رشته رمزگذاری شدهای را ارسال میکند و دادههای متن ساده را فقط برای خودش نگه میدارد. در این مرحله، زمان ارسال بلاک commitTime نیز ثبت میشود. در مرحله بعد، زمان بلاک در تابع ()detectSolution بررسی میشود تا از اجرای فرنت-رانینگ در همان بلوک جلوگیری شود. چون فراخوانی ()revelSolution مستلزم ارسال پاسخ متن ساده است، هدف این مرحله جلوگیری از دور زدن ()commitSolution توسط دیگران و فراخوانی مستقیم تابع ()zbulSolution است. پس از تأیید موفقیتآمیز، درصورتیکه پاسخ صحیح باشد، پاداش توزیع میشود.
نتیجهگیری
قراردادهای هوشمند نقشی مهم و مزایایی متعدد در فناوری بلاکچین دارند. اول اینکه، آنها اجرای غیرمتمرکز و خودکار را امکانپذیر میکنند و امنیت و قابلیت اطمینان تراکنشها را بدون نیاز به اشخاص ثالث تضمین میکنند. ثانیاً، قراردادهای هوشمند مراحل و هزینههای واسطهای را کاهش میدهند و کارایی معاملات را افزایش میدهند.
قراردادهای هوشمند، بهرغم مزایای بسیاری که دارند، با ریسک حملات، که خسارات مالی زیادی را به کاربران وارد میکنند، نیز روبرو هستند. بهاینترتیب، برخی از عادات برای کاربران زنجیرهای ضروری هستند. در مرحله اول، کاربران باید همیشه اپلیکیشنهای غیرمتمرکز را برای تعامل با دقت انتخاب کنند و کد قرارداد و قوانین مرتبط را به طور کامل بررسی کنند. بعلاوه، آنها باید به طور منظم کیف پولهای امن و ابزارهای تعامل قراردادی را برای کاهش ریسک حملات هکرها بهروزرسانی و استفاده کنند. بعلاوه، توصیه میشود وجوهتان را در آدرسهای متعددی ذخیره کنید تا ضررهای احتمالی ناشی از این حملات قراردادی کمینه شوند.
اطمینان از امنیت و ثبات قراردادهای هوشمند از اهمیت یکسانی برای بازیگران صنعت برخوردار است. اولویت اول باید تقویت حسابرسی قراردادهای هوشمند برای شناسایی و اصلاح آسیبپذیریها و خطرات امنیتی احتمالی باشد. اولویت دومشان باید اطلاع از آخرین تحولات بلاکچین درزمینهٔ حملات قراردادی باشد و اقدامات امنیتی لازم را بر همین اساس انجام دهند. آخرین نکته مهم آنکه، آنها باید آموزش کاربر و آگاهی امنیتی را ازنظر استفاده صحیح از قراردادهای هوشمند افزایش دهند.
در نتیجه، خطرات امنیتی ناشی از قراردادهای هوشمند را میتوان با تلاشهای هماهنگ کاربران و بازیگران صنعت به طور قابلتوجهی کاهش داد. کاربران باید همیشه قراردادها را با دقت انتخاب کنند و از داراییهای شخصی محافظت کنند. در مقابل، بازیگران صنعت نیز باید حسابرسی قراردادها را تشدید کنند، در جریان پیشرفتهای فناوری قرار بگیرند، و آموزش و آگاهی کاربران را افزایش دهند. باهم توسعه ایمن و قابلاعتماد قراردادهای هوشمند را پیش خواهیم برد.
منابع:
آموزش سالیدیتی از طریق مثال
https://solidity-by-example.org/
دانش بلاکچین SlowMist
چینلینک – 10 مورد از بهترین اقدامات امنیتی دیفای
https://blog.chain.link/defi-security-best-practices/#post-title
WTF- امنیت قرارداد Solidity 104
https://www.wtf.academy/solidity-104/
آسیبپذیری در قراردادهای هوشمند دیفای در 4 دسته با 38 سناریو
https://www.weiyangx.com/381670.html
OpenZeppelin