حسابرسی قرارداد هوشمند با ConsenSys Diligence Fuzzing – Fuzzing as a Service
اگر با قراردادهای هوشمند کار می کنید – یا حتی فقط در حال بررسی آنها هستید – احتمالاً از قبل می دانید که امنیت قراردادهای هوشمند مهم است. قراردادهای هوشمند پس از استقرار غیر قابل تغییر هستند و اغلب شامل مقادیر قابل توجهی پول می شوند. نوشتن کد ایمن و قابل اعتماد قبل از استقرار باید مهم باشد. و با تسریع پذیرش بلاک چین، اطمینان از امنیت قراردادهای هوشمند اهمیت بیشتری پیدا می کند.
یکی از بهترین موارد اضافه شده به حسابرسی قرارداد هوشمند شما، fuzzing است، یک تکنیک تست پویا که با تولید و تزریق ورودی های تصادفی به قراردادهای هوشمند شما در طول آزمایش، آسیب پذیری ها را آشکار می کند.
در این مقاله، نحوه استفاده از fuzzing برای ممیزی موثر قرارداد هوشمند را بررسی خواهیم کرد. به طور خاص، ConsenSys Diligence Fuzzing را بررسی خواهیم کرد – یک ارائه جدید فازی به عنوان یک سرویس (FaaS). ما به جنبه های فنی می پردازیم و چند نمونه کد را نشان می دهیم.
Fuzzing چیست؟
Fuzzing یک تکنیک تست پویا است که در آن ورودی های تصادفی (یا نیمه تصادفی) به نام “fuzz” تولید و به کد تزریق می شوند. Fuzzing میتواند به آشکار کردن باگها و آسیبپذیریهایی که توسط روشهای آزمایش سنتی کشف نشدهاند، کمک کند.
آزمایش دستی (واحد) از شما میخواهد که بفهمید چه عملکردی را باید آزمایش کنید، از چه ورودیهایی استفاده کنید، و خروجی مورد انتظار چقدر باید باشد. وقت گیر، دشوار است، و در نهایت، از دست دادن سناریوها همچنان آسان است.
از سوی دیگر، fuzzing (یا تست فازی) یک فرآیند تست خودکار است که دادههای تصادفی را به یک برنامه برای آزمایش امنیت آن ارسال میکند. یک fuzzer می تواند به شما کمک کند تا بفهمید یک برنامه چگونه به ورودی های غیرقابل پیش بینی پاسخ می دهد.
Fuzzing مدتی است که وجود دارد. Defensics و Burp Suite نمونه هایی در دنیای توسعه سنتی هستند. چندین ابزار fuzzing web3/blockchain نیز وجود دارد، مانند Echidna و Foundry. با این حال، Diligence Fuzzing به عنوان یک سرویس fuzzing است و اجرای همه چیز را کمی سادهتر میکند. که در نهایت به معنای ممیزی بهتر و قراردادهای مطمئن تر است. پس بیایید با جزئیات بیشتری به آن نگاه کنیم.
ConsenSys Diligence Fuzzing
Diligence Fuzzing (توسط ConsenSys که از استانداردهای اکوسیستم مانند MetaMask و Infura نیز پشتیبانی می کند) یک fuzzer است که برای قراردادهای هوشمند web3 ساخته شده است. آی تی:
-
از یک مشخصات رسمی کار می کند که رفتار مورد انتظار قرارداد هوشمند شما را توصیف می کند
-
توالی تراکنش هایی را ایجاد می کند که ممکن است ادعاهای شما را نقض کند
-
از تجزیه و تحلیل پیشرفته برای یافتن ورودی هایی استفاده می کند که حداکثر مقدار کد قرارداد هوشمند شما را پوشش می دهد
-
منطق تجاری برنامه را تأیید می کند و صحت عملکرد را بررسی می کند
-
هر یافته ای را در اختیار شما قرار می دهد
و همه به عنوان یک سرویس با حداقل کار از شما!
برای استفاده از Diligence Fuzzing این سه مرحله را دنبال کنید:
-
ابتدا مشخصات قرارداد هوشمند خود را با استفاده از Scribble تعریف کنید.
-
سپس، کد را به Diligence ارسال کنید تا fuzzing شما اجرا شود.
-
در نهایت با گزارش حسابرسی کد خود را اصلاح و بهبود دهید!
Fuzzing in Action
پس بیایید آن را آزمایش کنیم و آن را در عمل ببینیم. ما از Fuzzing CLI و Scribble برای تست فازی یک نمونه قرارداد هوشمند استفاده خواهیم کرد.
مرحله 1: ثبت نام کنید
ابتدا برای دسترسی به Diligence Fuzzing ثبت نام کنید.
مرحله 2: وابستگی ها را نصب کنید
سپس Fuzzing CLI و Scribble را نصب کنید. ConsenSys توصیه می کند که آخرین نسخه های Node و Python را داشته باشید. مطمئن شوید که حداقل از Python 3.6 و Node 16 استفاده می کنید. سپس:
pip3 install diligence-fuzzing
npm i -g eth-scribble ganache truffle
توجه: این به یک زیر سیستم لینوکس، مک یا لینوکس با ویندوز نیاز دارد. Windows Powershell دارای پیچیدگی هایی است که تیم روی آن کار می کند. همیشه می توانید از a استفاده کنید فضای کد github (که یک رابط VScode مانند با یک ساخت بوت استرپ تمیز ایجاد می کند) و پیش نیازهای بالا را از طریق خط فرمان نصب کنید.
مرحله 3: یک کلید API دریافت کنید
اکنون برای استفاده از CLI باید یک کلید API ایجاد کنید. از صفحه کلیدهای API دیدن کنید و روی Create new API Key کلیک کنید.
مرحله 4: پیکربندی فازی را تنظیم کنید
حالا ما نیاز به یک قرارداد هوشمند داریم تا fuzz کنیم! به عنوان بخشی از آموزش خود، ConsenSys یک نمونه قرارداد هوشمند برای استفاده ارائه می دهد. فقط از اون یکی استفاده کنیم
git clone https://github.com/ConsenSys/scribble-exercise-1.git
باز کن .fuzz.yml
از پروژه فایل کنید و کلید API خود را برای ویژگی “key” در حدود خط 25 اضافه کنید.
# .fuzz_token.yml
fuzz:
# Tell the CLI where to find the compiled contracts and compilation artifacts
build_directory: build/contracts
# The following address is going to be the main target for the fuzzing campaign
deployed_contract_address: "0xe78A0F7E598Cc8b0Bb87894B0F60dD2a88d6a8Ab"
# We'll do fuzzing with 2 cores 🚀
number_of_cores: 2
# Run the campaign for just 3 minutes.
time_limit: 3m
# Put the campaign in the Sribble Exercise 1 project
project: "Scribble Exercise 1"
# When the campaign is created it'll get a name <prefix>_<random_characters>
campaign_name_prefix: "ERC20 campaign"
# Point to your ganache node which holds the seed 🌱
rpc_url: "http://localhost:8545"
key: "INSERT YOUR API KEY HERE"
# This is the contract that the campaign will show coverage for/ map issues to etc
# It's a list of all the relevant contracts (don't worry about dependencies, we'll get those automatically 🙌)
targets:
- "contracts/vulnerableERC20.sol"
توجه: مطمئن شوید که کمپین های مبهم خود را متوقف کنید یا یک محدودیت زمانی تعیین کنید، در غیر این صورت ممکن است برای مدت طولانی غیرمنتظره ای اجرا شود. از فایل بالا متوجه خواهید شد که ما محدودیت زمانی کمپین های خود را سه دقیقه تعیین کرده ایم.
مرحله 5: ویژگی های fuzzing را تعریف کنید
همچنین توجه داشته باشید که ما قرارداد هوشمند خود را داریم: contracts/vulnerableERC20.sol
.
در مرحله بعد، باید ویژگی هایی را که می خواهیم فازر در قرارداد هوشمند بررسی کند، تعریف کنیم. برای این مرحله از Scribble استفاده می کنیم. Scribble یک زبان مشخصات است که مشخصات سطح بالا را به کد Solidity ترجمه می کند. این به شما امکان می دهد قراردادهای خود را با ویژگی ها حاشیه نویسی کنید و سپس آن حاشیه نویسی ها را به اظهارات ملموس تبدیل می کند که می تواند با ابزارهای آزمایشی (مانند Diligence Fuzzing) استفاده شود. خیلی باحال!
ما بخش های کد برجسته شده را به قرارداد خود اضافه می کنیم:
pragma solidity ^0.6.0;
/// #invariant "balances are in sync"
unchecked_sum(_balances) == _totalSupply;
contract VulnerableToken {
این حاشیه نویسی تضمین می کند که کل عرضه و موجودی ما همگام هستند.
مرحله 6: اجرا کنید
در حال حاضر ما fuzz! به سادگی این دستور را اجرا کنید:
make fuzz
مرحله 7: نتایج را ارزیابی کنید
پس از اتمام فازر (ممکن است راه اندازی یک یا دو دقیقه طول بکشد) می توانیم نتایج خود را دریافت کنیم. ما می توانیم از پیوندی که fuzzer به ما می دهد استفاده کنیم یا می توانیم به داشبورد خود برویم.
نگاه كردن خواص، ما میتوانیم ببینیم چه چیزی در حال مبهم شدن است و هر کدام تخلفات. و حدس بزنید چه؟ یک باگ پیدا کردیم! برای مشاهده کد توهین آمیز روی دکمه مکان خط کلیک کنید.
برای جزئیات، کلیک کنید نمایش جزئیات تراکنش. ما می توانیم فوزری به نام “انتقال” را ببینیم:
پس از بررسی دقیق تر، اکنون می توانیم ببینیم که چه چیزی باعث ایجاد باگ ما شده است.
آرگومان های transfer_to و مبدا یکسان هستند. هنگامی که شخصی برای خود توکن می فرستد باید یک آسیب پذیری امنیتی وجود داشته باشد. بیایید به کد منبع نگاه کنیم تا ببینیم مشکل چیست.
function transfer(address _to, uint256 _value) external returns (bool) {
address from = msg.sender;
require(_value <= _balances[from]);
uint256 newBalanceFrom = _balances[from] - _value;
uint256 newBalanceTo = _balances[_to] + _value;
_balances[from] = newBalanceFrom;
_balances[_to] = newBalanceTo;
emit Transfer(msg.sender, _to, _value);
return true;
}
بله! میتوانیم ببینیم که وقتی فرستنده و گیرنده یکسان هستند، خطوط 30 و 31 کمی عجیب و غریب میشوند—یکی در حال تغییر مقدار حساب «از» و دیگری در حال تغییر ارزش حساب «به» است. کد فرض می کند که آنها حساب های متفاوتی هستند. اما از آنجایی که آنها یک اکانت هستند، تا زمانی که به خط 31 برسیم، ارزشی که داریم آن چیزی نیست که انتظار داریم. قبلاً با خط قبلی تغییر کرده است.
ما میتوانیم با اضافه کردن خطوط کد مشخص شده در زیر این مشکل را برطرف کنیم:
function transfer(address _to, uint256 _value) external returns (bool) {
address from = msg.sender;
require(_value <= _balances[from]);
_balances[from] -= _value;
_balances[_to] += _value;
uint256 newBalanceFrom = _balances[from] - _value;
uint256 newBalanceTo = _balances[_to] + _value;
_balances[from] = newBalanceFrom;
_balances[_to] = newBalanceTo;
emit Transfer(msg.sender, _to, _value);
return true;
}
در اینجا چندین جزئیات فنی دیگر وجود دارد که باید از آنها آگاه باشید:
-
اسکریپت seed.js در اینجا مقداری کار راه اندازی را برای شما انجام می دهد. این قرارداد را در یک گره آزمایشی مستقر می کند. همچنین میتواند کارهایی مانند توکنهای نعناع، استخرهای باز و غیره را انجام دهد. حالت مناسبی را برای شروع به fuzzer میدهد.
-
فایل yml دارای پارامترهای پیکربندی زیادی است که می توانید آنها را بررسی کنید. به ویژه آدرس قرارداد به fuzz، کلید API، time_limit برای fuzzing، و برخی دیگر.
-
CLI با یک ژنراتور پیکربندی خودکار ارسال می شود. fuzz generate-config را اجرا کنید تا پرسش و پاسخ مفیدی برای ایجاد پیکربندی دریافت کنید.
حسابرسی قرارداد هوشمند – از Fuzzing استفاده کنید!
Fuzzing and Diligence Fuzzing-as-a-service ابزاری قدرتمند برای آزمایش ممیزی قراردادهای هوشمند بلاک چین اتریوم است. خواه در امور مالی غیرمتمرکز (DeFi)، NFTها، یا به تازگی توسعه قراردادهای هوشمند را شروع کرده اید، می تواند شما را به سطح بعدی شناسایی و رفع آسیب پذیری در قراردادهای هوشمند خود برساند. همراه با بررسی های دستی، تست های واحد، آزمایش دستی، تست نفوذ، بررسی کد و موارد دیگر، فازبندی باید بخش کلیدی فرآیند ممیزی امنیتی قرارداد هوشمند شما باشد تا یک پایگاه کد ایمن تر و قوی تر داشته باشید.
یک روز واقعا عالی داشته باشید!