এই নিবন্ধটি স্মার্ট কন্ট্রাক্ট সিকিউরিটির একটি মিনি-কোর্স হিসেবে কাজ করে এবং সলিডিটি স্মার্ট কন্ট্রাক্টে পুনরাবৃত্তি হওয়ার প্রবণতা এবং দুর্বলতার একটি বিস্তৃত তালিকা প্রদান করে। এগুলি এমন ধরণের সমস্যা যা একটি মানের অডিটে আসতে পারে।
সলিডিটিতে একটি নিরাপত্তা সমস্যা স্মার্ট কন্ট্রাক্টের মত আচরণ করে না যেভাবে তারা উদ্দেশ্য করে।
ফান্ড চুরি হচ্ছে
তহবিল একটি চুক্তির মধ্যে লক আপ বা হিমায়িত হচ্ছে
লোকেরা প্রত্যাশিত তুলনায় কম পুরষ্কার পায় (পুরস্কারগুলি বিলম্বিত বা হ্রাস করা হয়)
লোকেরা প্রত্যাশার চেয়ে বেশি পুরষ্কার পায় (যার ফলে মুদ্রাস্ফীতি এবং অবমূল্যায়ন হয়)
ভুল হতে পারে এমন সবকিছুর একটি বিস্তৃত তালিকা তৈরি করা সম্ভব নয়। যাইহোক, যেমন প্রথাগত সফ্টওয়্যার প্রকৌশলে এসকিউএল ইনজেকশন, বাফার ওভাররান এবং ক্রস সাইট স্ক্রিপ্টিংয়ের মতো দুর্বলতার সাধারণ থিম রয়েছে, তেমনি স্মার্ট চুক্তিতে পুনরাবৃত্তিমূলক অ্যান্টি-প্যাটার্ন রয়েছে যা নথিভুক্ত করা যেতে পারে।
এই নির্দেশিকাটিকে একটি রেফারেন্স হিসাবে আরও ভাবুন। এটিকে একটি বইতে পরিণত না করে সবকিছুর ধারণা নিয়ে বিস্তারিত আলোচনা করা সম্ভব নয় (ন্যায্য সতর্কতা: এই নিবন্ধটি 10k+ শব্দ দীর্ঘ, তাই নির্দ্বিধায় এটিকে বুকমার্ক করুন এবং খণ্ডে পড়ুন)। যাইহোক, এটি কীসের দিকে নজর দিতে হবে এবং কী অধ্যয়ন করতে হবে তার একটি তালিকা হিসাবে কাজ করে। যদি একটি বিষয় অপরিচিত বোধ করে, তবে এটি একটি সূচক হিসাবে কাজ করা উচিত যে সেই শ্রেণির দুর্বলতা চিহ্নিত করার অনুশীলনে সময় দেওয়া মূল্যবান।
এই নিবন্ধটি সলিডিটিতে মৌলিক দক্ষতা অনুমান করে। আপনি যদি সলিডিটিতে নতুন হন, তাহলে অনুগ্রহ করে আমাদের ফ্রি সলিডিটি টিউটোরিয়ালটি দেখুন।
আমরা স্মার্ট কন্ট্রাক্ট রিএন্ট্রান্সির বিষয়ে ব্যাপকভাবে লিখেছি তাই আমরা এখানে এটি পুনরাবৃত্তি করব না। কিন্তু এখানে একটি দ্রুত সারসংক্ষেপ:
যখনই একটি স্মার্ট চুক্তি অন্য একটি স্মার্ট চুক্তির ফাংশন কল করে, এতে ইথার পাঠায়, বা এটিতে একটি টোকেন স্থানান্তর করে, তখনই পুনরায় প্রবেশের সম্ভাবনা থাকে।
পুনঃপ্রবেশ সম্ভবত সবচেয়ে সুপরিচিত স্মার্ট চুক্তির দুর্বলতা হওয়া সত্ত্বেও, এটি শুধুমাত্র বন্য অঞ্চলে ঘটে যাওয়া হ্যাকগুলির একটি ছোট শতাংশ তৈরি করে। নিরাপত্তা গবেষক Pascal Caversaccio (pcaveraccio) পুনঃপ্রবেশ আক্রমণের একটি আপ-টু-ডেট গিথুব তালিকা রাখে। এপ্রিল 2023 পর্যন্ত, সেই সংগ্রহস্থলে 46টি পুনঃপ্রবেশ আক্রমণ নথিভুক্ত করা হয়েছে।
এটি একটি সাধারণ ভুল বলে মনে হচ্ছে, তবে কে একটি সংবেদনশীল ফাংশনকে কল করতে পারে তার উপর সীমাবদ্ধতা রাখতে ভুলে যাওয়া (যেমন ইথার প্রত্যাহার করা বা মালিকানা পরিবর্তন) আশ্চর্যজনকভাবে প্রায়শই ঘটে।
এমনকি যদি একটি সংশোধক জায়গায় থাকে, এমন কিছু ঘটনা ঘটেছে যেখানে সংশোধনকারী সঠিকভাবে প্রয়োগ করা হয়নি, যেমন নীচের উদাহরণে যেখানে প্রয়োজনীয় বিবৃতিটি অনুপস্থিত।
// DO NOT USE! modifier onlyMinter { minters[msg.sender] == true_; }
এই উপরের কোডটি এই অডিটের একটি বাস্তব উদাহরণ: https://code4rena.com/reports/2023-01-rabbithole/#h-01-bad-implementation-in-minter-access-control-for-rabbitholereceipt-and- rabbitholetickets-চুক্তি
এখানে অন্য উপায় অ্যাক্সেস নিয়ন্ত্রণ ভুল হতে পারে
function claimAirdrop(bytes32 calldata proof[]) { bool verified = MerkleProof.verifyCalldata(proof, merkleRoot, keccak256(abi.encode(msg.sender))); require(verified, "not verified"); require(alreadyClaimed[msg.sender], "already claimed"); _transfer(msg.sender, AIRDROP_AMOUNT); }
এই ক্ষেত্রে, "ইতিমধ্যেই দাবি করা" কখনই সত্য হিসাবে সেট করা হয় না, তাই দাবিকারী একাধিকবার ফাংশনটিকে কল করতে পারেন৷
অপর্যাপ্ত অ্যাক্সেস কন্ট্রোলের একটি মোটামুটি সাম্প্রতিক উদাহরণ ছিল একটি ট্রেডিং বট দ্বারা ফ্ল্যাশলোন গ্রহণের জন্য একটি অরক্ষিত ফাংশন (যা 0xbad নামে পরিচিত, কারণ ঠিকানাটি সেই ক্রম দিয়ে শুরু হয়েছিল)। এটি এক মিলিয়ন ডলারের বেশি মুনাফা অর্জন করেছে যতক্ষণ না একদিন একজন আক্রমণকারী লক্ষ্য করে যে কোনও ঠিকানা ফ্ল্যাশলোন রিসিভ ফাংশনকে কল করতে পারে, শুধুমাত্র ফ্ল্যাশলোন প্রদানকারীকে নয়।
সাধারণত ট্রেডিং বটগুলির ক্ষেত্রে যেমন হয়, ট্রেডগুলি চালানোর জন্য স্মার্ট চুক্তি কোডটি যাচাই করা হয়নি, তবে আক্রমণকারী যাইহোক দুর্বলতাটি আবিষ্কার করেছিল। Rekt সংবাদ কভারেজ আরো তথ্য.
যদি অ্যাক্সেস কন্ট্রোল একটি ফাংশন কে কল করে তা নিয়ন্ত্রণ করা হয়, ইনপুট বৈধতা হল তারা যে চুক্তির সাথে কল করে তা নিয়ন্ত্রণ করা।
এটি সাধারণত সঠিক প্রয়োজনীয় বিবৃতি স্থাপন করতে ভুলে যাওয়ার জন্য নেমে আসে।
এখানে একটি প্রাথমিক উদাহরণ:
contract UnsafeBank { mapping(address => uint256) public balances; // allow depositing on other's behalf function deposit(address for) public payable { balances += msg.value; } function withdraw(address from, uint256 amount) public { require(balances[from] <= amount, "insufficient balance"); balances[from] -= amount; msg.sender.call{value: amout}(""); } }
উপরের চুক্তিটি পরীক্ষা করে যে আপনি আপনার অ্যাকাউন্টের চেয়ে বেশি উত্তোলন করছেন না, তবে এটি আপনাকে একটি স্বেচ্ছাচারী অ্যাকাউন্ট থেকে তোলা থেকে বিরত করে না।
একটি বাহ্যিক ফাংশনের একটি প্যারামিটার স্যানিটাইজ না হওয়ার কারণে Sushiswap এই ধরনের একটি হ্যাক করেছে৷
অনুপযুক্ত অ্যাক্সেস নিয়ন্ত্রণ মানে msg.sender-এর পর্যাপ্ত সীমাবদ্ধতা নেই। অনুপযুক্ত ইনপুট বৈধতা মানে ফাংশনের আর্গুমেন্টগুলি পর্যাপ্তভাবে স্যানিটাইজ করা হয়নি। এই অ্যান্টি-প্যাটার্নের একটি বিপরীতও রয়েছে: একটি ফাংশন কলে খুব বেশি সীমাবদ্ধতা স্থাপন করা।
অত্যধিক বৈধতার অর্থ সম্ভবত তহবিল চুরি হবে না, তবে এর অর্থ চুক্তিতে তহবিল আটকে যেতে পারে। জায়গায় অনেকগুলি সুরক্ষা ব্যবস্থা থাকাও ভাল জিনিস নয়।
সবচেয়ে হাই-প্রোফাইল ঘটনাগুলির মধ্যে একটি ছিল আকুটারস এনএফটি যা স্মার্ট চুক্তির ভিতরে আটকে থাকা 34 মিলিয়ন ডলার মূল্যের ইথ এবং প্রত্যাহারযোগ্য নয়।
ডাচ নিলাম মূল্যের উপরে পরিশোধ করা থেকে সমস্ত অর্থ ফেরত দেওয়া না হওয়া পর্যন্ত চুক্তির মালিককে প্রত্যাহার করা থেকে বিরত রাখার জন্য চুক্তিটির একটি ভাল উদ্দেশ্যমূলক ব্যবস্থা ছিল। কিন্তু নীচে লিঙ্ক করা টুইটার থ্রেডে নথিভুক্ত একটি বাগের কারণে, মালিক তহবিল তুলতে পারেনি।
Sushiswap অবিশ্বস্ত ব্যবহারকারীদের অনেক বেশি ক্ষমতা দিয়েছে, এবং Akutars NFT অ্যাডমিনকে খুব কম ক্ষমতা দিয়েছে। স্মার্ট কন্ট্রাক্ট ডিজাইন করার সময়, প্রতিটি শ্রেণীর ব্যবহারকারীদের কতটা স্বাধীনতা দেওয়া উচিত সে সম্পর্কে একটি বিষয়গত রায় এবং এই সিদ্ধান্তটি স্বয়ংক্রিয় পরীক্ষা এবং টুলিংয়ের উপর ছেড়ে দেওয়া যাবে না। বিকেন্দ্রীকরণ, নিরাপত্তা এবং UX এর সাথে উল্লেখযোগ্য ট্রেডঅফ রয়েছে যা অবশ্যই বিবেচনা করা উচিত।
স্মার্ট কন্ট্রাক্ট প্রোগ্রামারের জন্য, নির্দিষ্ট ফাংশনগুলির সাথে ব্যবহারকারীদের কী করা উচিত এবং কী করা উচিত নয় তা স্পষ্টভাবে লেখা উন্নয়ন প্রক্রিয়ার একটি গুরুত্বপূর্ণ অংশ।
আমরা পরে অতিরিক্ত ক্ষমতাপ্রাপ্ত প্রশাসকদের বিষয়ে পুনরায় পরিদর্শন করব।
ভূমিকায় বলা হয়েছে, স্মার্ট কন্ট্রাক্ট হ্যাক হওয়ার চারটি প্রাথমিক উপায় রয়েছে:
এখানে "টাকা" মানে মূল্যবান কিছু, যেমন টোকেন, শুধু ক্রিপ্টোকারেন্সি নয়। একটি স্মার্ট চুক্তির কোডিং বা অডিট করার সময়, ডেভেলপারকে অবশ্যই চুক্তির ভিতরে এবং বাইরে প্রবাহিত করার উদ্দেশ্য সম্পর্কে সচেতন হতে হবে। উপরে তালিকাভুক্ত সমস্যাগুলি হল স্মার্ট কন্ট্রাক্ট হ্যাক হওয়ার প্রাথমিক উপায়, তবে আরও অনেকগুলি মূল কারণ রয়েছে যা প্রধান সমস্যাগুলিতে ক্যাসকেড করতে পারে, যা নীচে নথিভুক্ত করা হয়েছে।
ভ্যানিলা ERC20 টোকেন বা NFTs ব্যবহার করে ভোটের ওজন করার জন্য টিকিট হিসেবে ব্যবহার করা অনিরাপদ কারণ আক্রমণকারীরা একটি ঠিকানা দিয়ে ভোট দিতে পারে, অন্য ঠিকানায় টোকেন স্থানান্তর করতে পারে এবং সেই ঠিকানা থেকে আবার ভোট দিতে পারে।
এখানে একটি ন্যূনতম উদাহরণ:
// A malicious voter can simply transfer their tokens to // another address and vote again. contract UnsafeBallot { uint256 public proposal1VoteCount; uint256 public proposal2VoteCount; IERC20 immutable private governanceToken; constructor(IERC20 _governanceToken) { governanceToken = _governanceToken; } function voteFor1() external notAlreadyVoted { proposal1VoteCount += governanceToken.balanceOf(msg.sender); } function voteFor2() external notAlreadyVoted { proposal2VoteCount += governanceToken.balanceOf(msg.sender); } // prevent the same address from voting twice, // however the attacker can simply // transfer to a new address modifier notAlreadyVoted { require(!alreadyVoted[msg.sender], "already voted"); _; alreadyVoted[msg.sender] = true; } }
এই আক্রমণ প্রতিরোধ করতে, ERC20 স্ন্যাপশট বা ERC20 ভোট ব্যবহার করা উচিত। অতীতের একটি বিন্দুর স্ন্যাপশট করে, বর্তমান টোকেন ব্যালেন্স অবৈধ ভোটিং ক্ষমতা লাভের জন্য ব্যবহার করা যাবে না।
যাইহোক, একটি স্ন্যাপশট বা ভোটের ক্ষমতা সহ একটি ERC20 টোকেন ব্যবহার করলে সমস্যার সম্পূর্ণ সমাধান হয় না যদি কেউ সাময়িকভাবে তাদের ব্যালেন্স বাড়ানোর জন্য একটি ফ্ল্যাশলোন নিতে পারে, তারপর একই লেনদেনে তাদের ব্যালেন্সের একটি স্ন্যাপশট নিন। যদি সেই স্ন্যাপশটটি ভোট দেওয়ার জন্য ব্যবহার করা হয়, তাহলে তাদের হাতে অযৌক্তিকভাবে বড় পরিমাণ ভোট থাকবে।
একটি ফ্ল্যাশলোন একটি ঠিকানায় প্রচুর পরিমাণে ইথার বা টোকেন ধার দেয়, কিন্তু একই লেনদেনে অর্থ পরিশোধ না করা হলে তা ফেরত যায়।
contract SimpleFlashloan { function borrowERC20Tokens() public { uint256 before = token.balanceOf(address(this)); // send tokens to the borrower token.transfer(msg.sender, amount); // hand control back to the borrower to // let them do something IBorrower(msg.sender).onFlashLoan(); // require that the tokens got returned require(token.balanceOf(address(this) >= before); } }
একজন আক্রমণকারী হঠাৎ করে অনেক ভোট পেতে একটি ফ্ল্যাশলোন ব্যবহার করতে পারে এবং/অথবা দূষিত কিছু করতে পারে।
এটি তর্কযোগ্যভাবে DeFi-তে সবচেয়ে সাধারণ (বা অন্তত সবচেয়ে হাই-প্রোফাইল) আক্রমণ, যার ফলে শত শত মিলিয়ন ডলার ক্ষতি হয়েছে। এখানে হাই প্রোফাইল বেশী একটি তালিকা আছে.
ব্লকচেইনে একটি সম্পদের মূল্য প্রায়ই সম্পদের মধ্যে বর্তমান বিনিময় হার হিসাবে গণনা করা হয়। উদাহরণস্বরূপ, যদি একটি চুক্তি বর্তমানে 100 k9coin এর জন্য 1 USDC ট্রেড করে, তাহলে আপনি বলতে পারেন k9coin এর মূল্য 0.01 USDC। যাইহোক, দাম সাধারণত ক্রয়-বিক্রয়ের চাপের প্রতিক্রিয়ায় চলে যায় এবং ফ্ল্যাশ লোন ব্যাপক ক্রয়-বিক্রয়ের চাপ তৈরি করতে পারে।
একটি সম্পদের মূল্য সম্পর্কে অন্য একটি স্মার্ট চুক্তির জন্য জিজ্ঞাসা করার সময়, বিকাশকারীকে খুব সতর্কতা অবলম্বন করতে হবে কারণ তারা ধরে নিচ্ছে যে তারা যে স্মার্ট চুক্তিটি কল করছে তা ফ্ল্যাশ লোন ম্যানিপুলেশন থেকে অনাক্রম্য।
আপনি "চেক" করতে পারেন যে ঠিকানাটি একটি স্মার্ট চুক্তি কিনা সেটির বাইটকোড আকার দেখে৷ বাহ্যিক মালিকানাধীন অ্যাকাউন্টে (নিয়মিত ওয়ালেট) কোনো বাইটকোড নেই। এখানে এটি করার কয়েকটি উপায় রয়েছে
import "@openzeppelin/contracts/utils/Address.sol" contract CheckIfContract { using Address for address; function addressIsContractV1(address _a) { return _a.code.length == 0; } function addressIsContractV2(address _a) { // use the openzeppelin libraryreturn _a.isContract(); } }
যাইহোক, এর কিছু সীমাবদ্ধতা রয়েছে
একটি ঠিকানা একটি চুক্তি কিনা তা সাধারণভাবে পরীক্ষা করা সাধারণত (কিন্তু সবসময় নয়) একটি অ্যান্টিপ্যাটার্ন। মাল্টিসিগনেচার ওয়ালেটগুলি নিজেরাই স্মার্ট চুক্তি, এবং মাল্টিসিগনেচার ওয়ালেটগুলিকে ভেঙে ফেলতে পারে এমন কিছু করলে কম্পোজেবিলিটি ভেঙে যায়।
এর ব্যতিক্রম হল একটি ট্রান্সফার হুক কল করার আগে লক্ষ্যটি একটি স্মার্ট চুক্তি কিনা তা পরীক্ষা করা। এই বিষয়ে পরে আরো.
tx.origin ব্যবহার করার জন্য খুব কমই একটি ভাল কারণ আছে। যদি tx.origin প্রেরককে শনাক্ত করতে ব্যবহার করা হয়, তাহলে একটি ম্যান-ইন-দ্য-মিডল আক্রমণ সম্ভব। যদি ব্যবহারকারীকে একটি দূষিত স্মার্ট চুক্তি কল করার জন্য প্রতারিত করা হয়, তাহলে স্মার্ট চুক্তিটি tx.origin-কে ধ্বংস করার জন্য সমস্ত কর্তৃপক্ষ ব্যবহার করতে পারে।
এই নিম্নলিখিত অনুশীলন এবং কোড উপরে মন্তব্য বিবেচনা করুন.
contract Phish { function phishingFunction() public { // this fails, because this contract does not have approval/allowance token.transferFrom(msg.sender, address(this), token.balanceOf(msg.sender)); // this also fails, because this creates approval for the contract,// not the wallet calling this phishing function token.approve(address(this), type(uint256).max); } }
এর অর্থ এই নয় যে আপনি নির্বিচারে স্মার্ট চুক্তিগুলিকে নিরাপদে কল করছেন৷ কিন্তু বেশিরভাগ প্রোটোকলের মধ্যে নিরাপত্তার একটি স্তর তৈরি করা হয়েছে যা প্রমাণীকরণের জন্য tx.origin ব্যবহার করা হলে তা বাইপাস করা হবে।
কখনও কখনও, আপনি এইরকম দেখতে কোড দেখতে পারেন:
require(msg.sender == tx.origin, "no contracts");
যখন একটি স্মার্ট চুক্তি অন্য একটি স্মার্ট চুক্তিতে কল করে, তখন msg.sender হবে স্মার্ট চুক্তি এবং tx.origin হবে ব্যবহারকারীর ওয়ালেট, এইভাবে একটি নির্ভরযোগ্য ইঙ্গিত দেয় যে ইনকামিং কলটি একটি স্মার্ট চুক্তি থেকে এসেছে৷ কনস্ট্রাক্টর থেকে কল আসলেও এটি সত্য।
বেশিরভাগ সময়, এই নকশা প্যাটার্ন একটি ভাল ধারণা নয়। EIP 4337 এর মাল্টিসিগনেচার ওয়ালেট এবং ওয়ালেট এই কোড আছে এমন একটি ফাংশনের সাথে ইন্টারঅ্যাক্ট করতে সক্ষম হবে না। এই প্যাটার্নটি সাধারণত NFT টাকশালে দেখা যায়, যেখানে বেশিরভাগ ব্যবহারকারী একটি ঐতিহ্যগত ওয়ালেট ব্যবহার করছেন বলে আশা করা যুক্তিসঙ্গত। কিন্তু অ্যাকাউন্ট বিমূর্ততা আরও জনপ্রিয় হয়ে উঠলে, এই প্যাটার্নটি সাহায্য করার চেয়ে বেশি বাধা দেবে।
একটি শোকজনক আক্রমণ মানে হ্যাকার অন্য লোকেদের জন্য "দুঃখের কারণ" করার চেষ্টা করছে, এমনকি যদি তারা এটি করে অর্থনৈতিকভাবে লাভ না করে।
একটি স্মার্ট চুক্তি দূষিতভাবে একটি অসীম লুপে গিয়ে এটিতে পাঠানো সমস্ত গ্যাস ব্যবহার করতে পারে। নিম্নলিখিত উদাহরণ বিবেচনা করুন:
contract Mal { fallback() external payable { // infinite loop uses up all the gas while (true) { } } }
যদি অন্য একটি চুক্তি নিম্নরূপ ঠিকানাগুলির একটি তালিকায় ইথার বিতরণ করে:
contract Distribute { funtion distribute(uint256 total) public nonReentrant { for (uint i; i < addresses.length; ) { (bool ok, ) addresses.call{value: total / addresses.length}(""); // ignore ok, if it reverts we move on // traditional gas saving trick for for loops unchecked { ++i; } } } }
তারপর ফাংশনটি রিভার্ট হবে যখন এটি ইথার ম্যালে পাঠাবে। উপরের কোডে কলটি উপলব্ধ গ্যাসের 63/64 ফরোয়ার্ড করে, তাই সম্ভবত শুধুমাত্র 1/64 গ্যাস অবশিষ্ট রেখে অপারেশন সম্পূর্ণ করার জন্য যথেষ্ট গ্যাস থাকবে না।
একটি স্মার্ট চুক্তি একটি বৃহৎ মেমরি অ্যারে ফেরত দিতে পারে যা প্রচুর গ্যাস ব্যবহার করে
নিম্নলিখিত উদাহরণ বিবেচনা করুন
function largeReturn() public { // result might be extremely long! (book ok, bytes memory result) = otherContract.call(abi.encodeWithSignature("foo()")); require(ok, "call failed"); }
মেমরি অ্যারেগুলি 724 বাইটের পরে দ্বিঘাত পরিমাণ গ্যাস ব্যবহার করে, তাই একটি সাবধানে নির্বাচিত রিটার্ন ডেটা সাইজ কলকারীকে দুঃখ দিতে পারে।
পরিবর্তনশীল ফলাফল ব্যবহার না করা হলেও, এটি এখনও মেমরিতে অনুলিপি করা হয়। আপনি যদি একটি নির্দিষ্ট পরিমাণে রিটার্নের আকার সীমাবদ্ধ করতে চান তবে আপনি সমাবেশ ব্যবহার করতে পারেন
function largeReturn() public { assembly { let ok := call(gas(), destinationAddress, value, dataOffset, dataSize, 0x00, 0x00); // nothing is copied to memory until you // use returndatacopy() } }
যদিও স্টোরেজ মুছে ফেলা একটি গ্যাস-দক্ষ ক্রিয়াকলাপ, তবুও এটির একটি নিট খরচ রয়েছে। একটি অ্যারে খুব দীর্ঘ হয়ে গেলে, এটি মুছে ফেলা অসম্ভব হয়ে ওঠে। এখানে একটি ন্যূনতম উদাহরণ
contract VulnerableArray { address[] public stuff; function addSomething(address something) public { stuff.push(something); } // if stuff is too long, this will become undeletable due to // the gas cost function deleteEverything() public onlyOwner { delete stuff; } }
যদি একটি স্মার্ট কন্ট্রাক্ট ট্রান্সফার হুক আছে এমন টোকেন স্থানান্তর করে, তাহলে একজন আক্রমণকারী একটি চুক্তি সেট আপ করতে পারে যা টোকেন গ্রহণ করে না (এটিতে হয় অনরিসিভ ফাংশন থাকে না বা ফাংশনটি প্রত্যাবর্তনের জন্য প্রোগ্রাম করে)। এটি টোকেনটিকে হস্তান্তর অযোগ্য করে তুলবে এবং পুরো লেনদেনকে ফিরিয়ে আনবে।
নিরাপদ ট্রান্সফার বা স্থানান্তর ব্যবহার করার আগে, রিসিভার লেনদেনটি প্রত্যাবর্তন করতে বাধ্য করতে পারে এমন সম্ভাবনা বিবেচনা করুন।
contract Mal is IERC721Receiver, IERC1155Receiver, IERC777Receiver { // this will intercept any transfer hook fallback() external payable { // infinite loop uses up all the gaswhile (true) { } } // we could also selectively deny transactions function onERC721Received(address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4) { if (wakeUpChooseViolence()) { revert(); } else { return IERC721Receiver.onERC721Received.selector; } } }
ব্লকচেইনে একক লেনদেনের মাধ্যমে নিরাপদে এলোমেলোতা তৈরি করা বর্তমানে সম্ভব নয়। ব্লকচেইনগুলি সম্পূর্ণরূপে নির্ধারক হতে হবে, অন্যথায় বিতরণ করা নোডগুলি রাষ্ট্র সম্পর্কে ঐকমত্যে পৌঁছাতে সক্ষম হবে না। যেহেতু তারা সম্পূর্ণরূপে নির্ধারক, যেকোন "এলোমেলো" সংখ্যা ভবিষ্যদ্বাণী করা যেতে পারে। নিম্নলিখিত পাশা রোলিং ফাংশন শোষণ করা যেতে পারে.
contract UnsafeDice { function randomness() internal returns (uint256) { return keccak256(abi.encode(msg.sender, tx.origin, block.timestamp, tx.gasprice, blockhash(block.number - 1); } // our dice can land on one of {0,1,2,3,4,5}function rollDice() public payable { require(msg.value == 1 ether); if (randomness() % 6) == 5) { msg.sender.call{value: 2 ether}(""); } } } contract ExploitDice { function randomness() internal returns (uint256) { return keccak256(abi.encode(msg.sender, tx.origin, block.timestamp, tx.gasprice, blockhash(block.number - 1); } function betSafely(IUnsafeDice game) public payable { if (randomness % 6) == 5)) { game.betSafely{value: 1 ether}() } // else don't do anything } }
আপনি কীভাবে এলোমেলোতা তৈরি করেন তা বিবেচ্য নয় কারণ আক্রমণকারী এটিকে ঠিক প্রতিলিপি করতে পারে। msg.sender, টাইমস্ট্যাম্প ইত্যাদির মতো "এনট্রপি"-এর আরও উত্সগুলিতে নিক্ষেপ করা কোনও প্রভাব ফেলবে না কারণ স্মার্ট চুক্তি এটি দুটি পরিমাপ করতে পারে।
নিরাপদ র্যান্ডম নম্বর পেতে চেইনলিংক একটি জনপ্রিয় সমাধান। এটি দুটি ধাপে এটি করে। প্রথমে, স্মার্ট চুক্তিগুলি ওরাকলকে একটি এলোমেলোতার অনুরোধ পাঠায়, তারপরে কিছু ব্লক পরে, ওরাকল একটি এলোমেলো নম্বর দিয়ে প্রতিক্রিয়া জানায়।
যেহেতু একজন আক্রমণকারী ভবিষ্যতের ভবিষ্যদ্বাণী করতে পারে না, তাই তারা এলোমেলো সংখ্যার ভবিষ্যদ্বাণী করতে পারে না।
যদি না স্মার্ট চুক্তি ওরাকল ভুল ব্যবহার করে।
একটি নির্দিষ্ট সময়সীমার মধ্যে এটির মূল্য ওরাকল আপ টু ডেট রাখার জন্য চেইনলিংকের জন্য কোনও SLA (পরিষেবা স্তরের চুক্তি) নেই। যখন শৃঙ্খলটি গুরুতরভাবে জ্যামিত হয় (যেমন যখন Yuga Labs Otherside মিন্ট কোন লেনদেন না হওয়ার কারণে Ethereum কে অভিভূত করে ), মূল্য আপডেট বিলম্বিত হতে পারে।
একটি স্মার্ট চুক্তি যা একটি মূল্য ওরাকল ব্যবহার করে তা অবশ্যই স্পষ্টভাবে পরীক্ষা করতে হবে যে ডেটা পুরানো নয়, অর্থাৎ সম্প্রতি কিছু থ্রেশহোল্ডের মধ্যে আপডেট করা হয়েছে। অন্যথায়, এটি দামের ক্ষেত্রে একটি নির্ভরযোগ্য সিদ্ধান্ত নিতে পারে না।
একটি অতিরিক্ত জটিলতা রয়েছে যে যদি মূল্য একটি বিচ্যুতি থ্রেশহোল্ডের পরে পরিবর্তিত না হয়, তাহলে ওরাকল গ্যাস সংরক্ষণের জন্য মূল্য আপডেট নাও করতে পারে, তাই এটি কোন সময় থ্রেশহোল্ডকে "বাসি" হিসাবে বিবেচনা করা হয় তা প্রভাবিত করতে পারে।
একটি স্মার্ট চুক্তির উপর নির্ভর করে একটি ওরাকলের SLA বোঝা গুরুত্বপূর্ণ৷
একটি ওরাকল যতই নিরাপদ মনে হোক না কেন, ভবিষ্যতে একটি আক্রমণ আবিষ্কৃত হতে পারে। এর বিরুদ্ধে একমাত্র প্রতিরক্ষা হল একাধিক স্বাধীন ওরাকল ব্যবহার করা।
ব্লকচেইন বেশ সুরক্ষিত হতে পারে, কিন্তু প্রথমে চেইনে ডেটা রাখার জন্য একধরনের অফ-চেইন অপারেশনের প্রয়োজন হয় যা ব্লকচেইন প্রদানকারী সমস্ত নিরাপত্তা গ্যারান্টি ত্যাগ করে। এমনকি যদি ওরাকল সৎ থাকে, তবে তাদের তথ্যের উৎস হেরফের করা যেতে পারে। উদাহরণস্বরূপ, একটি ওরাকল নির্ভরযোগ্যভাবে একটি কেন্দ্রীভূত এক্সচেঞ্জ থেকে দামের রিপোর্ট করতে পারে, কিন্তু সেগুলি বড় ক্রয়-বিক্রয় আদেশের সাথে ব্যবহার করা যেতে পারে। একইভাবে, ওরাকল যেগুলি সেন্সর ডেটা বা কিছু ওয়েব2 API-এর উপর নির্ভর করে সেগুলি ঐতিহ্যগত হ্যাকিং ভেক্টরের অধীন।
একটি ভাল স্মার্ট কন্ট্রাক্ট আর্কিটেকচার যেখানে সম্ভব সেখানে ওরাকলের ব্যবহার সম্পূর্ণভাবে এড়িয়ে যায়।
নিম্নলিখিত চুক্তি বিবেচনা করুন
contract MixedAccounting { uint256 myBalance; function deposit() public payable { myBalance = myBalance + msg.value; } function myBalanceIntrospect() public view returns (uint256) { return address(this).balance; } function myBalanceVariable() public view returns (uint256) { return myBalance; } function notAlwaysTrue() public view returns (bool) { return myBalanceIntrospect() == myBalanceVariable(); } }
উপরের চুক্তিতে রিসিভ বা ফলব্যাক ফাংশন নেই, তাই সরাসরি ইথারে স্থানান্তর করা হলে তা প্রত্যাবর্তন করবে। যাইহোক, একটি চুক্তি জোরপূর্বক স্ব-ধ্বংসের সাথে ইথার পাঠাতে পারে।
সেক্ষেত্রে, myBalanceIntrospect() myBalanceVariable() এর থেকে বড় হবে। ইথার অ্যাকাউন্টিং পদ্ধতি ঠিক আছে, কিন্তু আপনি যদি উভয়ই ব্যবহার করেন, তাহলে চুক্তিতে অসামঞ্জস্যপূর্ণ আচরণ থাকতে পারে।
একই ERC20 টোকেন জন্য প্রযোজ্য.
contract MixedAccountingERC20 { IERC20 token; uint256 myTokenBalance; function deposit(uint256 amount) public { token.transferFrom(msg.sender, address(this), amount); myTokenBalance = myTokenBalance + amount; } function myBalanceIntrospect() public view returns (uint256) { return token.balanceOf(address(this)); } function myBalanceVariable() public view returns (uint256) { return myTokenBalance; } function notAlwaysTrue() public view returns (bool) { return myBalanceIntrospect() == myBalanceVariable(); } }
আবার আমরা অনুমান করতে পারি না যে myBalanceIntrospect() এবং myBalanceVariable() সর্বদা একই মান প্রদান করবে। ডিপোজিট ফাংশন বাইপাস করে এবং myTokenBalance ভেরিয়েবল আপডেট না করে সরাসরি ERC20 টোকেন MixedAccountingERC20 এ স্থানান্তর করা সম্ভব।
আত্মদর্শনের সাথে ভারসাম্য পরীক্ষা করার সময়, সমতা যাচাইয়ের কঠোর ব্যবহার এড়ানো উচিত কারণ ভারসাম্যটি একজন বহিরাগত ইচ্ছামত পরিবর্তন করতে পারে।
এটি সলিডিটির ছলনা নয়, ঠিকানাগুলিকে বিশেষ সুবিধা দিতে কীভাবে ক্রিপ্টোগ্রাফি ব্যবহার করতে হয় সে সম্পর্কে বিকাশকারীদের মধ্যে একটি সাধারণ ভুল বোঝাবুঝি। নিম্নলিখিত কোডটি অনিরাপদ
contract InsecureMerkleRoot { bytes32 merkleRoot; function airdrop(bytes[] calldata proof, bytes32 leaf) external { require(MerkleProof.verifyCalldata(proof, merkleRoot, leaf), "not verified"); require(!alreadyClaimed[leaf], "already claimed airdrop"); alreadyClaimed[leaf] = true; mint(msg.sender, AIRDROP_AMOUNT); } }
ক্রিপ্টোগ্রাফিক প্রমাণ (মার্কেল গাছ, স্বাক্ষর, ইত্যাদি) msg.sender-এর সাথে আবদ্ধ করা প্রয়োজন, যা একজন আক্রমণকারী ব্যক্তিগত কী অর্জন না করে ব্যবহার করতে পারে না।
function limitedMultiply(uint8 a, uint8 b) public pure returns (uint256 product) { product = a * b; }
যদিও পণ্যটি একটি uint256 পরিবর্তনশীল, গুণের ফলাফল 255 এর চেয়ে বড় হতে পারে না বা কোডটি প্রত্যাবর্তন করা হবে।
প্রতিটি ভেরিয়েবলকে পৃথকভাবে আপকাস্ট করে এই সমস্যাটি প্রশমিত করা যেতে পারে।
function unlimitedMultiply(uint8 a, uint8 b) public pure returns (uint256 product) { product = uint256(a) * uint256(b); }
এই ধরনের একটি পরিস্থিতি ঘটতে পারে যদি একটি স্ট্রাকটে পূর্ণসংখ্যাকে গুণ করা হয়। একটি স্ট্রাকটে প্যাক করা ছোট মানগুলিকে গুন করার সময় আপনার এটি সম্পর্কে সচেতন হওয়া উচিত
struct Packed { uint8 time; uint16 rewardRate } //... Packed p; p.time * p.rewardRate; // this might revert!
দৃঢ়তা পরীক্ষা করে না যে এটি একটি ছোট পূর্ণসংখ্যাকে নিক্ষেপ করা নিরাপদ কিনা। যতক্ষণ না কিছু ব্যবসায়িক যুক্তি নিশ্চিত করে যে ডাউনকাস্টিং নিরাপদ, সেফকাস্টের মতো একটি লাইব্রেরি ব্যবহার করা উচিত।
function test(int256 value) public pure returns (int8) { return int8(value + 1); // overflows and does not revert }
কোডটি দেখে মনে হচ্ছে এটি myArray[1]-এ myArray[0]-এ ডেটা কপি করে, কিন্তু তা করে না। আপনি যদি ফাংশনের চূড়ান্ত লাইনটি মন্তব্য করেন, কম্পাইলার বলবে ফাংশনটিকে একটি ভিউ ফাংশনে পরিণত করা উচিত। foo-এ লেখা অন্তর্নিহিত সঞ্চয়স্থানে লেখা হয় না।
contract DoesNotWrite { struct Foo { uint256 bar; } Foo[] public myArray; function moveToSlot0() external { Foo storage foo = myArray[0]; foo = myArray[1]; // myArray[0] is unchanged // we do this to make the function a state // changing operation // and silence the compiler warning myArray[1] = Foo({bar: 100}); } }
তাই স্টোরেজ পয়েন্টার লিখবেন না.
যদি একটি ম্যাপিং (বা গতিশীল অ্যারে) একটি স্ট্রাকটের ভিতরে থাকে এবং স্ট্রাকটটি মুছে ফেলা হয়, ম্যাপিং বা অ্যারে মুছে ফেলা হবে না।
একটি অ্যারে মুছে ফেলার ব্যতিক্রম ছাড়া, ডিলিট কীওয়ার্ড শুধুমাত্র একটি স্টোরেজ স্লট মুছতে পারে। যদি স্টোরেজ স্লটে অন্যান্য স্টোরেজ স্লটের উল্লেখ থাকে, সেগুলি মুছে ফেলা হবে না।
contract NestedDelete { mapping(uint256 => Foo) buzz; struct Foo { mapping(uint256 => uint256) bar; } Foo foo; function addToFoo(uint256 i) external { buzz[i].bar[5] = 6; } function getFromFoo(uint256 i) external view returns (uint256) { return buzz[i].bar[5]; } function deleteFoo(uint256 i) external { // internal map still holds the data in the // mapping and array delete buzz[i]; } }
মনে রাখবেন, সলিডিটিতে মানচিত্র কখনই "খালি" হয় না। তাই যদি কেউ মুছে ফেলা কোনো আইটেম অ্যাক্সেস করে, তাহলে লেনদেনটি প্রত্যাবর্তন করবে না বরং সেই ডেটাটাইপের জন্য শূন্য মান ফেরত দেবে।
আপনি যদি শুধুমাত্র বিশ্বস্ত ERC20 টোকেন নিয়ে কাজ করেন তবে এই সমস্যাগুলির বেশিরভাগই প্রযোজ্য হবে না। যাইহোক, যখন একটি নির্বিচারে বা আংশিকভাবে অবিশ্বস্ত ERC20 টোকেনের সাথে ইন্টারঅ্যাক্ট করা হয়, তখন এখানে কিছু বিষয় খেয়াল রাখতে হবে।
অবিশ্বস্ত টোকেনগুলির সাথে ডিল করার সময়, আপনার মনে করা উচিত নয় যে আপনার ব্যালেন্স অগত্যা পরিমাণ দ্বারা বৃদ্ধি পাবে৷ একটি ERC20 টোকেনের পক্ষে এটির স্থানান্তর ফাংশন নিম্নরূপ বাস্তবায়ন করা সম্ভব:
contract ERC20 { // internally called by transfer() and transferFrom() // balance and approval checks happen in the caller function _transfer(address from, address to, uint256 amount) internal returns (bool) { fee = amount * 100 / 99; balanceOf[from] -= to; balanceOf[to] += (amount - fee); balanceOf[TREASURY] += fee; emit Transfer(msg.sender, to, (amount - fee)); return true; } }
এই টোকেনটি প্রতিটি লেনদেনের জন্য 1% ট্যাক্স প্রযোজ্য। সুতরাং যদি একটি স্মার্ট চুক্তি নিম্নরূপ টোকেনের সাথে ইন্টারঅ্যাক্ট করে, আমরা হয় অপ্রত্যাশিত প্রত্যাবর্তন বা চুরি করা অর্থ পাব।
contract Stake { mapping(address => uint256) public balancesInContract; function stake(uint256 amount) public { token.transferFrom(msg.sender, address(this), amount); balancesInContract[msg.sender] += amount; // THIS IS WRONG! } function unstake() public { uint256 toSend = balancesInContract[msg.sender]; delete balancesInContract[msg.sender]; // this could revert because toSend is 1% greater than// the amount in the contract. Otherwise, 1% will be "stolen"// from other depositors. token.transfer(msg.sender, toSend); } }
রিবেসিং টোকেনটি অলিম্পাস DAO- এর sOhm টোকেন এবং Ampleforth-এর AMPL টোকেন দ্বারা জনপ্রিয় হয়েছিল। Coingecko ERC20 টোকেন পুনর্বাসনের একটি তালিকা বজায় রাখে।
যখন একটি টোকেন রিবেস হয়, তখন মোট সরবরাহ পরিবর্তিত হয় এবং রিবেসের দিকনির্দেশের উপর নির্ভর করে প্রত্যেকের ভারসাম্য বৃদ্ধি বা হ্রাস পায়।
একটি রিবেসিং টোকেন নিয়ে কাজ করার সময় নিম্নলিখিত কোডটি ভাঙার সম্ভাবনা রয়েছে
contract WillBreak { mapping(address => uint256) public balanceHeld; IERC20 private rebasingToken function deposit(uint256 amount) external { balanceHeld[msg.sender] = amount; rebasingToken.transferFrom(msg.sender, address(this), amount); } function withdraw() external { amount = balanceHeld[msg.sender]; delete balanceHeld[msg.sender]; // ERROR, amount might exceed the amount // actually held by the contract rebasingToken.transfer(msg.sender, amount); } }
অনেক চুক্তির সমাধান হল রিবেসিং টোকেনগুলিকে অস্বীকৃতি জানানো। যাইহোক, প্রেরকের কাছে অ্যাকাউন্টের ব্যালেন্স স্থানান্তর করার আগে ব্যালেন্স অফ(ঠিকানা(এই)) চেক করতে উপরের কোডটি পরিবর্তন করতে পারে। তারপর ভারসাম্য পরিবর্তন হলেও এটি কাজ করবে।
ERC20, মান অনুযায়ী প্রয়োগ করা হলে, ERC20 টোকেনগুলিতে ট্রান্সফার হুক থাকে না, এবং এইভাবে স্থানান্তর এবং স্থানান্তর থেকে পুনরায় প্রবেশের সমস্যা হয় না।
ট্রান্সফার হুক সহ টোকেনগুলির অর্থপূর্ণ সুবিধা রয়েছে, এই কারণেই সমস্ত NFT মান সেগুলি প্রয়োগ করে এবং কেন ERC777 চূড়ান্ত করা হয়েছিল। যাইহোক, এটি যথেষ্ট বিভ্রান্তির সৃষ্টি করেছে যে ওপেনজেপেলিন ERC777 লাইব্রেরি অবমূল্যায়িত করেছে ।
আপনি যদি চান যে আপনার প্রোটোকল এমন টোকেনগুলির সাথে সামঞ্জস্যপূর্ণ হতে পারে যা ERC20 টোকেনের মতো আচরণ করে কিন্তু ট্রান্সফার হুক থাকে, তাহলে ফাংশন ট্রান্সফার এবং ট্রান্সফারের সাথে আচরণ করা একটি সহজ ব্যাপার যেমন তারা রিসিভারকে একটি ফাংশন কল ইস্যু করবে।
এই ERC777 পুনঃপ্রবেশ ঘটেছে Uniswap (ওপেনজেপেলিন এখানে শোষণের নথিভুক্ত করেছেন যদি আপনি আগ্রহী হন)।
ERC20 স্পেসিফিকেশন নির্দেশ করে যে একটি ERC20 টোকেন অবশ্যই সত্য হতে হবে যখন একটি স্থানান্তর সফল হয়। যেহেতু ভাতা অপর্যাপ্ত না হলে বা স্থানান্তরিত পরিমাণ অত্যধিক না হলে বেশিরভাগ ERC20 বাস্তবায়ন ব্যর্থ হতে পারে না, বেশিরভাগ devs ERC20 টোকেনের রিটার্ন মান উপেক্ষা করতে অভ্যস্ত হয়ে উঠেছে এবং অনুমান করে একটি ব্যর্থ স্থানান্তর ফিরে আসবে।
সত্যি বলতে কি, যদি আপনি শুধুমাত্র একটি বিশ্বস্ত ERC20 টোকেনের সাথে কাজ করেন যার আচরণ আপনি জানেন তাহলে এটি ফলপ্রসূ নয়। কিন্তু নির্বিচারে ERC20 টোকেন নিয়ে কাজ করার সময়, আচরণের এই বৈচিত্রের জন্য অবশ্যই হিসাব করা উচিত।
অনেক চুক্তিতে একটি অন্তর্নিহিত প্রত্যাশা রয়েছে যে ব্যর্থ স্থানান্তরগুলি সর্বদা প্রত্যাবর্তন করা উচিত, মিথ্যা ফেরত দেওয়া উচিত নয় কারণ বেশিরভাগ ERC20 টোকেনগুলিতে মিথ্যা ফেরত দেওয়ার কোনও ব্যবস্থা নেই, তাই এটি অনেক বিভ্রান্তির জন্ম দিয়েছে।
এই বিষয়টিকে আরও জটিল করে তুলেছে যে কিছু ERC20 টোকেন সত্য প্রত্যাবর্তনের প্রোটোকল অনুসরণ করে না, বিশেষত Tether। কিছু টোকেন স্থানান্তর করতে ব্যর্থ হলে প্রত্যাবর্তন করে, যার ফলে প্রত্যাবর্তন কলারের কাছে বুদবুদ হয়ে যায়। এইভাবে, কিছু লাইব্রেরি ইআরসি20 টোকেন ট্রান্সফার কলগুলিকে প্রত্যাবর্তনকে বাধা দিতে এবং পরিবর্তে একটি বুলিয়ান ফেরত দেয়।
সোলাডি সেফ ট্রান্সফার (অনেক বেশি গ্যাস দক্ষ)
এটি একটি স্মার্ট চুক্তির দুর্বলতা নয়, তবে আমরা এটি সম্পূর্ণতার জন্য এখানে উল্লেখ করছি।
স্পেসিফিকেশন দ্বারা শূন্য ERC20 টোকেন স্থানান্তর অনুমোদিত। এটি ফ্রন্টএন্ড অ্যাপ্লিকেশনগুলির জন্য বিভ্রান্তির কারণ হতে পারে এবং ব্যবহারকারীরা সম্প্রতি কাকে টোকেন পাঠিয়েছেন সে সম্পর্কে সম্ভাব্য কৌশল করতে পারে। এই থ্রেডে মেটামাস্কের আরও কিছু রয়েছে।
(ওয়েব 3 শব্দে "রাগড" মানে "আপনার নিচ থেকে পাটি বের করে আনা।")
কাউকে একটি ERC20 টোকেনে একটি ফাংশন যোগ করা থেকে বাধা দেওয়ার কিছু নেই যা তাদের ইচ্ছামতো টোকেন তৈরি, স্থানান্তর এবং বার্ন করতে দেয় — বা স্ব-ধ্বংস বা আপগ্রেড করতে। তাই মৌলিকভাবে, একটি ERC20 টোকেন কতটা "অবিশ্বস্ত" হতে পারে তার একটা সীমা আছে।
ধার দেওয়া এবং ধার নেওয়া ভিত্তিক ডিফাই প্রোটোকলগুলি কীভাবে ভাঙতে পারে তা বিবেচনা করার সময়, সফ্টওয়্যার স্তরে বাগগুলি প্রচার করা এবং ব্যবসায়িক যুক্তি স্তরকে প্রভাবিত করার বিষয়ে চিন্তা করা সহায়ক। একটি বন্ড চুক্তি গঠন এবং বন্ধ করার জন্য অনেক পদক্ষেপ আছে। এখানে কিছু আক্রমণ ভেক্টর বিবেচনা করতে হবে।
যদি প্রোটোকল থেকে জামানত বাদ দেওয়া হয়, তাহলে ঋণদাতা এবং ঋণগ্রহীতা উভয়ই হারাবেন, যেহেতু ঋণগ্রহীতার ঋণ ফেরত দেওয়ার জন্য কোন প্রণোদনা নেই, এবং ঋণগ্রহীতা মূল হারায়।
উপরে দেখা যায়, একটি DeFi প্রোটোকলের "হ্যাক" হওয়ার অনেক বেশি স্তর রয়েছে প্রোটোকল থেকে একগুচ্ছ অর্থ নিষ্কাশনের চেয়ে (যে ধরনের ঘটনাগুলি সাধারণত সংবাদ তৈরি করে)। এটি এমন একটি এলাকা যেখানে CTF (পতাকা ক্যাপচার) নিরাপত্তা অনুশীলন বিভ্রান্তিকর হতে পারে। যদিও প্রোটোকল তহবিল চুরি হওয়া সবচেয়ে বিপর্যয়কর পরিণতি, তবে এটির বিরুদ্ধে রক্ষা করার একমাত্র উপায় নয়।
একটি বাহ্যিক স্মার্ট চুক্তি কল করার দুটি উপায় আছে: 1) একটি ইন্টারফেস সংজ্ঞা সহ ফাংশন কল করা; 2) কল পদ্ধতি ব্যবহার করে। এই নীচে চিত্রিত করা হয়
contract A { uint256 public x; function setx(uint256 _x) external { require(_x > 10, "x must be bigger than 10"); x = _x; } } interface IA { function setx(uint256 _x) external; } contract B { function setXV1(IA a, uint256 _x) external { a.setx(_x); } function setXV2(address a, uint256 _x) external { (bool success, ) = a.call(abi.encodeWithSignature("setx(uint256)", _x)); // success is not checked! } }
চুক্তি B-এ, setXV2 নীরবে ব্যর্থ হতে পারে যদি _x 10-এর কম হয়। যখন একটি ফাংশন .call পদ্ধতির মাধ্যমে কল করা হয়, তখন callee প্রত্যাবর্তন করতে পারে, কিন্তু অভিভাবক প্রত্যাবর্তন করবে না। সাফল্যের মান অবশ্যই পরীক্ষা করা উচিত এবং কোড আচরণ সেই অনুযায়ী শাখা হতে হবে।
ব্যক্তিগত ভেরিয়েবলগুলি এখনও ব্লকচেইনে দৃশ্যমান, তাই সংবেদনশীল তথ্য সেখানে কখনই সংরক্ষণ করা উচিত নয়। যদি তারা অ্যাক্সেসযোগ্য না হয়, তাহলে যাচাইকারীরা কীভাবে তাদের মূল্যের উপর নির্ভর করে এমন লেনদেন প্রক্রিয়া করতে সক্ষম হবে? প্রাইভেট ভেরিয়েবলগুলি বাইরের সলিডিটি চুক্তি থেকে পড়া যায় না, তবে সেগুলি একটি Ethereum ক্লায়েন্ট ব্যবহার করে অফ-চেইন পড়া যেতে পারে।
একটি ভেরিয়েবল পড়তে, আপনাকে এর স্টোরেজ স্লট জানতে হবে। নিম্নলিখিত উদাহরণে, myPrivateVar এর স্টোরেজ স্লট হল 0।
// SPDX-License-Identifier: MIT pragma solidity ^0.8.0; contract PrivateVarExample { uint256 private myPrivateVar; constructor(uint256 _initialValue) { myPrivateVar = _initialValue; } }
স্থাপন করা স্মার্ট চুক্তির ব্যক্তিগত ভেরিয়েবল পড়ার জন্য এখানে জাভাস্ক্রিপ্ট কোড রয়েছে
const Web3 = require("web3"); const PRIVATE_VAR_EXAMPLE_ADDRESS = "0x123..."; // Replace with your contract address async function readPrivateVar() { const web3 = new Web3("http://localhost:8545"); // Replace with your provider's URL // Read storage slot 0 (where 'myPrivateVar' is stored) const storageSlot = 0; const privateVarValue = await web3.eth.getStorageAt( PRIVATE_VAR_EXAMPLE_ADDRESS, storageSlot ); console.log("Value of private variable 'myPrivateVar':", web3.utils.hexToNumberString(privateVarValue)); } readPrivateVar();
ডেলিগেটকল কখনই অবিশ্বস্ত চুক্তির সাথে ব্যবহার করা উচিত নয় কারণ এটি ডেলিগেটক্যালের সমস্ত নিয়ন্ত্রণ হস্তান্তর করে। এই উদাহরণে, অবিশ্বস্ত চুক্তি চুক্তির সমস্ত ইথার চুরি করে।
contract UntrustedDelegateCall { constructor() payable { require(msg.value == 1 ether); } function doDelegateCall(address _delegate, bytes calldata data) public { (bool ok, ) = _delegate.delegatecall(data); require(ok, "delegatecall failed"); } } contract StealEther { function steal() public { // you could also selfdestruct here // if you really wanted to be mean (bool ok,) = tx.origin.call{value: address(this).balance}(""); require(ok); } function attack(address victim) public { UntrustedDelegateCall(victim).doDelegateCall( address(this), abi.encodeWithSignature("steal()")); } }
আমরা একটি বিভাগে এই বিষয় সুবিচার করতে পারেন না. বেশিরভাগ আপগ্রেড বাগগুলি সাধারণত Openzeppelin থেকে হার্ডহ্যাট প্লাগইন ব্যবহার করে এবং এটি কোন সমস্যা থেকে রক্ষা করে সে সম্পর্কে পড়ার মাধ্যমে এড়ানো যায়। ( https://docs.openzeppelin.com/upgrades-plugins/1.x/ )।
শুধুমাত্র একটি চুক্তির একজন মালিক বা প্রশাসক থাকার কারণে, এর অর্থ এই নয় যে তাদের ক্ষমতা সীমাহীন হতে হবে। একটি NFT বিবেচনা করুন. শুধুমাত্র মালিকের জন্য NFT বিক্রয় থেকে উপার্জন প্রত্যাহার করা যুক্তিসঙ্গত, তবে চুক্তিটি (ব্লক স্থানান্তর) বিরাম দিতে সক্ষম হওয়া যদি মালিকের ব্যক্তিগত কীগুলির সাথে আপোস করা হয় তবে তা ধ্বংস হয়ে যেতে পারে। সাধারণত, অপ্রয়োজনীয় ঝুঁকি কমানোর জন্য প্রশাসকের সুযোগ-সুবিধা যতটা সম্ভব কম হওয়া উচিত।
চুক্তির মালিকানার কথা বলছি...
এটি প্রযুক্তিগতভাবে একটি দুর্বলতা নয়, তবে মালিকানা অস্তিত্বহীন ঠিকানায় স্থানান্তর করা হলে ওপেনজেপেলিনের মালিকানা চুক্তির মালিকানা হারাতে পারে। Ownable2step-এর মালিকানা নিশ্চিত করতে রিসিভার প্রয়োজন। এটি ভুলবশত ভুল টাইপ করা ঠিকানায় মালিকানা পাঠানোর বিরুদ্ধে বীমা করে।
দৃঢ়তার ফ্লোট নেই, তাই রাউন্ডিং ত্রুটিগুলি অনিবার্য। ডিজাইনারকে অবশ্যই সচেতন হতে হবে যে সঠিক জিনিসটি রাউন্ড আপ করা বা রাউন্ড ডাউন করা এবং কার পক্ষে রাউন্ডিং করা উচিত।
বিভাগ সবসময় শেষ সঞ্চালিত করা উচিত. নিম্নোক্ত কোডটি স্থির কয়েনের মধ্যে ভুলভাবে রূপান্তরিত করে যার দশমিকের একটি ভিন্ন সংখ্যা রয়েছে। নিম্নলিখিত এক্সচেঞ্জ মেকানিজম একজন ব্যবহারকারীকে ডাই (যার 18 দশমিক 18 আছে) বিনিময় করার সময় বিনামূল্যে অল্প পরিমাণ USDC (যার মধ্যে 6 দশমিক আছে) নিতে পারবেন। ভেরিয়েবল daiToTake শূন্যে বৃত্তাকার হয়ে যাবে, নন-জিরো usdcAmount এর বিনিময়ে ব্যবহারকারীর কাছ থেকে কিছুই নেবে না।
contract Exchange { uint256 private constant CONVERSION = 1e12; function swapDAIForUSDC(uint256 usdcAmount) external pure returns (uint256 a) { uint256 daiToTake = usdcAmount / CONVERSION; conductSwap(daiToTake, usdcAmount); } }
Etheruem (এবং অনুরূপ চেইন) এর প্রেক্ষাপটে সামনে এগিয়ে যাওয়ার অর্থ হল একটি মুলতুবি লেনদেন পর্যবেক্ষণ করা এবং উচ্চতর গ্যাসের মূল্য পরিশোধ করে তার আগে অন্য লেনদেন সম্পাদন করা। অর্থাৎ, আক্রমণকারী লেনদেনের "সামনে দৌড়েছে"। যদি লেনদেনটি একটি লাভজনক বাণিজ্য হয়, তাহলে উচ্চতর গ্যাসের মূল্য পরিশোধ করা ছাড়া লেনদেনটি হুবহু কপি করা বোধগম্য। এই ঘটনাটিকে কখনও কখনও MEV হিসাবে উল্লেখ করা হয়, যার অর্থ খনির নিষ্কাশনযোগ্য মান, কিন্তু কখনও কখনও অন্যান্য প্রসঙ্গে সর্বাধিক নিষ্কাশনযোগ্য মান। ব্লক প্রযোজকদের লেনদেন পুনর্বিন্যাস করার এবং তাদের নিজস্ব সন্নিবেশ করার সীমাহীন ক্ষমতা রয়েছে এবং ঐতিহাসিকভাবে, ইথেরিয়াম স্টেকের প্রমাণে যাওয়ার আগে ব্লক প্রযোজকরা খনি শ্রমিক ছিলেন, তাই এই নাম।
একটি স্মার্ট চুক্তি থেকে ইথার প্রত্যাহার করা একটি "লাভজনক বাণিজ্য" হিসাবে বিবেচিত হতে পারে। আপনি একটি শূন্য-খরচের লেনদেন সম্পাদন করেন (গ্যাস বাদ দিয়ে) এবং আপনি শুরু করেছিলেন তার চেয়ে বেশি ক্রিপ্টোকারেন্সি দিয়ে শেষ করেন।
contract UnprotectedWithdraw { constructor() payable { require(msg.value == 1 ether, "must create with 1 eth"); } function unsafeWithdraw() external { (bool ok, ) = msg.sender.call{value: address(this).value}(""); require(ok, "transfer failed"). } }
আপনি যদি এই চুক্তিটি স্থাপন করেন এবং প্রত্যাহার করার চেষ্টা করেন, একটি অগ্রগামী বট মেমপুলে "অনিরাপদ প্রত্যাহার" করার জন্য আপনার কলটি লক্ষ্য করবে এবং প্রথমে ইথার পেতে এটি অনুলিপি করবে।
আমরা আমাদের ERC4626 টিউটোরিয়ালে ERC-4626 মুদ্রাস্ফীতি আক্রমণ সম্পর্কে গভীরভাবে লিখেছি। কিন্তু এর সারাংশ হল যে একটি ERC4626 চুক্তি একজন ব্যবসায়ীর অবদানের "সম্পদ" শতাংশের উপর ভিত্তি করে "শেয়ার" টোকেন বিতরণ করে।
মোটামুটিভাবে, এটি নিম্নরূপ কাজ করে:
function getShares(...) external { // code shares_received = assets_contributed / total_assets; // more code }
অবশ্যই, কেউ সম্পদে অবদান রাখবে না এবং কোন শেয়ার ফেরত পাবে না, তবে কেউ যদি শেয়ার পেতে বাণিজ্যে এগিয়ে যেতে পারে তবে তারা তা ঘটবে তা ভবিষ্যদ্বাণী করতে পারে না।
উদাহরণস্বরূপ, তারা 200টি সম্পদ অবদান রাখে যখন পুলের 20টি থাকে, তারা 100টি শেয়ার পাওয়ার আশা করে। কিন্তু যদি কেউ 200টি সম্পদ জমা করার জন্য লেনদেনকে সামনের দিকে চালায়, তাহলে সূত্রটি হবে 200/220, যা শূন্যে নেমে আসে, যার ফলে ক্ষতিগ্রস্ত ব্যক্তি সম্পদ হারাতে পারে এবং শূন্য শেয়ার ফিরে পায়।
এটি বিমূর্তভাবে বর্ণনা করার পরিবর্তে একটি বাস্তব উদাহরণ দিয়ে এটি ব্যাখ্যা করা ভাল
এখন ইভের কাছে 100 বা 50 এর পরিবর্তে 150টি টোকেন রয়েছে। এর সমাধান হল অবিশ্বস্ত অনুমোদনের সাথে কাজ করার সময় এটিকে বৃদ্ধি বা হ্রাস করার আগে অনুমোদনকে শূন্যে সেট করা।
ক্রয়-বিক্রয়ের চাপের প্রতিক্রিয়ায় একটি সম্পদের দাম বাড়ে। যদি একটি বড় অর্ডার মেমপুলে বসে থাকে, ব্যবসায়ীদের অর্ডারটি অনুলিপি করার জন্য একটি প্রণোদনা থাকে তবে উচ্চ গ্যাসের দাম সহ। এইভাবে, তারা সম্পদ ক্রয় করে, বড় অর্ডারে দাম বাড়তে দেয়, তারপর তারা এখনই বিক্রি করে। বিক্রয় আদেশকে কখনও কখনও "ব্যাকরানিং" বলা হয়। কম গ্যাসের দাম দিয়ে সেল অর্ডার দিয়ে বিক্রির অর্ডার করা যেতে পারে যাতে সিকোয়েন্সটি এরকম দেখায়
এই আক্রমণের বিরুদ্ধে প্রাথমিক প্রতিরক্ষা হল একটি "স্লিপেজ" প্যারামিটার প্রদান করা। যদি "ফ্রন্টরান বাই" নিজেই দামকে একটি নির্দিষ্ট থ্রেশল্ড অতিক্রম করে, তাহলে "বড় কেনা" অর্ডারটি ফেরত যাবে যার ফলে ফ্রন্টরানার বাণিজ্যে ব্যর্থ হবে।
এটাকে স্যান্ডউইচ বলা হয়, কারণ বড় কেনাকে স্যান্ডউইচ করা হয় ফ্রন্টরান বাই এবং ব্যাকরান সেল দ্বারা। এই আক্রমণটি বড় বিক্রির আদেশের সাথেও কাজ করে, ঠিক বিপরীত দিকে।
সামনে এগিয়ে যাওয়া একটি বিশাল বিষয়। Flashbots বিষয়টি নিয়ে ব্যাপকভাবে গবেষণা করেছে এবং এর নেতিবাচক বাহ্যিকতা কমাতে সাহায্য করার জন্য বেশ কিছু টুল এবং গবেষণা নিবন্ধ প্রকাশ করেছে।
সঠিক ব্লকচেইন আর্কিটেকচারের সাহায্যে সামনের দৌড়কে "পরিকল্পিত" করা যেতে পারে কিনা তা বিতর্কের একটি বিষয় যা চূড়ান্তভাবে নিষ্পত্তি করা হয়নি। নিম্নলিখিত দুটি নিবন্ধ এই বিষয়ে স্থায়ী ক্লাসিক:
স্মার্ট চুক্তির প্রসঙ্গে ডিজিটাল স্বাক্ষরের দুটি ব্যবহার রয়েছে:
একজন ব্যবহারকারীকে একটি NFT মিন্ট করার বিশেষাধিকার দিতে নিরাপদে ডিজিটাল স্বাক্ষর ব্যবহার করার একটি উদাহরণ এখানে দেওয়া হল:
import "@openzeppelin/contracts/utils/cryptography/ECDSA.sol"; import "@openzeppelin/contracts/token/ERC721/ERC721.sol"; contract NFT is ERC721("name", "symbol") { function mint(bytes calldata signature) external { address recovered = keccak256(abi.encode(msg.sender)).toEthSignedMessageHash().recover(signature); require(recovered == authorizer, "signature does not match"); } }
একটি ক্লাসিক উদাহরণ হল ERC20-এ অনুমোদন কার্যকারিতা। আমাদের অ্যাকাউন্ট থেকে নির্দিষ্ট পরিমাণ টোকেন তোলার জন্য একটি ঠিকানা অনুমোদন করতে, আমাদের একটি প্রকৃত ইথেরিয়াম লেনদেন করতে হবে, যার জন্য গ্যাস খরচ হয়।
এটি কখনও কখনও প্রাপকের অফ-চেইনে একটি ডিজিটাল স্বাক্ষর পাস করা আরও দক্ষ, তারপর প্রাপক স্মার্ট চুক্তিতে স্বাক্ষর সরবরাহ করে প্রমাণ করতে যে তারা লেনদেন পরিচালনা করার জন্য অনুমোদিত।
ERC20Permit একটি ডিজিটাল স্বাক্ষর সহ অনুমোদন সক্ষম করে। ফাংশনটি নিম্নরূপ বর্ণনা করা হয়েছে
function permit(address owner, address spender, uint256 amount, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) public
একটি প্রকৃত অনুমোদন লেনদেন পাঠানোর পরিবর্তে, মালিক ব্যয়কারীর অনুমোদনে "সই" করতে পারেন (একটি সময়সীমা সহ)। অনুমোদিত খরচকারী তারপর প্রদত্ত পরামিতি সহ পারমিট ফাংশন কল করতে পারেন।
আপনি ভেরিয়েবল দেখতে পাবেন, v, r, এবং s ঘন ঘন। এগুলি যথাক্রমে uint8, বাইট32 এবং বাইট32 ডেটাটাইপগুলির সাথে দৃঢ়তার সাথে উপস্থাপন করা হয়। কখনও কখনও, স্বাক্ষরগুলিকে 65 বাইট অ্যারে হিসাবে উপস্থাপন করা হয় যা এই সমস্ত মানগুলিকে একত্রে abi.encodePacked(r, s, v);
একটি স্বাক্ষরের অন্যান্য দুটি অপরিহার্য উপাদান হল বার্তা হ্যাশ (32 বাইট) এবং স্বাক্ষর করার ঠিকানা। ক্রম এই মত দেখায়
একটি ব্যক্তিগত কী (privKey) একটি সর্বজনীন ঠিকানা (ethAddress) তৈরি করতে ব্যবহৃত হয়
একটি স্মার্ট চুক্তি আগাম ethAddress সংরক্ষণ করে
একজন অফচেইন ব্যবহারকারী একটি বার্তা হ্যাশ করে এবং হ্যাশে স্বাক্ষর করে। এটি জোড়া msgHash এবং স্বাক্ষর তৈরি করে (r, s, v)
স্মার্ট চুক্তি একটি বার্তা গ্রহণ করে, এটিকে msgHash তৈরি করতে হ্যাশ করে, তারপর এটিকে (r, s, v) এর সাথে একত্রিত করে তা দেখতে কী ঠিকানা বেরিয়ে আসে।
ঠিকানাটি যদি ethAddress এর সাথে মেলে, তাহলে স্বাক্ষরটি বৈধ (নির্দিষ্ট অনুমানের অধীনে যা আমরা শীঘ্রই দেখতে পাব!)
স্মার্ট কন্ট্রাক্ট 4 ধাপে প্রি-কম্পাইল করা কন্ট্রাক্ট ইক্রিকভার ব্যবহার করে যা আমরা কম্বিনেশন বলেছি এবং ঠিকানা ফেরত পেতে পারি।
এই প্রক্রিয়ার অনেকগুলি ধাপ রয়েছে যেখানে জিনিসগুলি পাশে যেতে পারে।
এটি একটি দুর্বলতার দিকে নিয়ে যেতে পারে যদি একটি শুরু না করা ভেরিয়েবলকে ইক্রেভারের আউটপুটের সাথে তুলনা করা হয়।
এই কোড দুর্বল
contract InsecureContract { address signer; // defaults to address(0) // who lets us give the beneficiary the airdrop without them// spending gas function airdrop(address who, uint256 amount, uint8 v, bytes32 r, bytes32 s) external { // ecrecover returns address(0) if the signature is invalid require(signer == ecrecover(keccak256(abi.encode(who, amount)), v, r, s), "invalid signature"); mint(msg.sender, AIRDROP_AMOUNT); } }
স্বাক্ষর রিপ্লে ঘটে যখন একটি চুক্তি ট্র্যাক করে না যদি একটি স্বাক্ষর আগে ব্যবহার করা হয়েছে। নিম্নলিখিত কোডে, আমরা আগের সমস্যাটি ঠিক করেছি, কিন্তু এটি এখনও নিরাপদ নয়।
contract InsecureContract { address signer; function airdrop(address who, uint256 amount, uint8 v, bytes32 r, bytes32 s) external { address recovered == ecrecover(keccak256(abi.encode(who, amount)), v, r, s); require(recovered != address(0), "invalid signature"); require(recovered == signer, "recovered signature not equal signer"); mint(msg.sender, amount); } }
মানুষ যতবার খুশি ততবার এয়ারড্রপ দাবি করতে পারে!
আমরা নিম্নলিখিত লাইন যোগ করতে পারে
bytes memory signature = abi.encodePacked(v, r, s); require(!used[signature], "signature already used"); // mapping(bytes => bool); used[signature] = true;
হায়রে, কোড এখনও নিরাপদ নয়!
একটি বৈধ স্বাক্ষর দেওয়া হলে, একটি আক্রমণকারী একটি ভিন্ন একটি প্রাপ্ত করার জন্য কিছু দ্রুত পাটিগণিত করতে পারে। আক্রমণকারী তখন এই পরিবর্তিত স্বাক্ষরটিকে "পুনরায় খেলতে" পারে। কিন্তু প্রথমে, আসুন কিছু কোড প্রদান করি যা দেখায় যে আমরা একটি বৈধ স্বাক্ষর দিয়ে শুরু করতে পারি, এটি সংশোধন করতে পারি এবং দেখাতে পারি যে নতুন স্বাক্ষর এখনও পাস হচ্ছে।
contract Malleable { // v = 28 // r = 0xf8479d94c011613baeffe9239e4ff65e2adbac744c34217ca7d51378e72c5204 // s = 0x57af17590a914b759c45aaeabaf513d5ef72d7da1bdd19d9f2e1bc371ece5b86 // m = 0x0000000000000000000000000000000000000000000000000000000000000003 function foo(bytes calldata msg, uint8 v, bytes32 r, bytes32 s) public pure returns (address, address){ bytes32 h = keccak256(msg); address a = ecrecover(h, v, r, s); // The following is math magic to invert the // signature and create a valid one // flip s bytes32 s2 = bytes32(uint256(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141) - uint256(s)); // invert v uint8 v2; require(v == 27 || v == 28, "invalid v"); v2 = v == 27 ? 28 : 27; address b = ecrecover(h, v2, r, s2); assert(a == b); // different signatures, same address!; return (a, b); } }
যেমন, আমাদের চলমান উদাহরণ এখনও দুর্বল। একবার কেউ একটি বৈধ স্বাক্ষর উপস্থাপন করলে, এটির মিরর ইমেজ স্বাক্ষর তৈরি করা যেতে পারে এবং ব্যবহৃত স্বাক্ষর চেক বাইপাস করা যেতে পারে।
contract InsecureContract { address signer; function airdrop(address who, uint256 amount, uint8 v, bytes32 r, bytes32 s) external { address recovered == ecrecover(keccak256(abi.encode(who, amount)), v, r, s); require(recovered != address(0), "invalid signature"); require(recovered == signer, "recovered signature not equal signer"); bytes memory signature = abi.encodePacked(v, r, s); require(!used[signature], "signature already used"); // this can be bypassed used[signature] = true; mint(msg.sender, amount); } }
আপনি সম্ভবত এই সময়ে কিছু নিরাপদ স্বাক্ষর কোড চাইছেন, তাই না? আমরা আপনাকে দৃঢ়তার সাথে স্বাক্ষর তৈরি এবং ফাউন্ড্রিতে পরীক্ষা করার বিষয়ে আমাদের টিউটোরিয়ালটি উল্লেখ করি।
কিন্তু এখানে চেকলিস্ট আছে.
উপরের আক্রমণটিকে আরও সাধারণীকরণ করা যেতে পারে যদি চেইনে হ্যাশিং করা না হয়। উপরের উদাহরণগুলিতে, হ্যাশিংটি স্মার্ট চুক্তিতে করা হয়েছিল, তাই উপরের উদাহরণগুলি নিম্নলিখিত শোষণের জন্য ঝুঁকিপূর্ণ নয়৷
আসুন স্বাক্ষর পুনরুদ্ধারের জন্য কোডটি দেখি
// this code is vulnerable! function recoverSigner(bytes32 hash, uint8 v, bytes32 r, bytes32 s) public returns (address signer) { require(signer == ecrecover(hash, v, r, s), "signer does not match"); // more actions }
ব্যবহারকারী হ্যাশ এবং স্বাক্ষর উভয়ই সরবরাহ করে। যদি আক্রমণকারী ইতিমধ্যেই স্বাক্ষরকারীর কাছ থেকে একটি বৈধ স্বাক্ষর দেখে থাকে, তাহলে তারা সহজভাবে অন্য বার্তার হ্যাশ এবং স্বাক্ষর পুনঃব্যবহার করতে পারে।
এই কারণেই স্মার্ট চুক্তিতে বার্তাটি হ্যাশ করা খুবই গুরুত্বপূর্ণ, অফ-চেইন নয়।
এই শোষণকে কার্যকরভাবে দেখতে, আমরা টুইটারে যে CTF পোস্ট করেছি তা দেখুন।
পার্ট 1: https://twitter.com/RareSkills_io/status/1650869999266037760
পার্ট 2: https://twitter.com/RareSkills_io/status/1650897671543197701
https://twitter.com/RareSkills_io/status/1651527648676573185 https://twitter.com/RareSkills_io/status/1651224817465540611
ব্যবহারকারীদের সনাক্ত করতে স্বাক্ষর ব্যবহার করা উচিত নয়। নমনীয়তার কারণে, তাদের অনন্য বলে ধরে নেওয়া যায় না। Msg.sender অনেক শক্তিশালী স্বতন্ত্রতা গ্যারান্টি আছে.
আমরা এখানে টুইটারে হোস্ট করা একটি নিরাপত্তা অনুশীলন দেখুন। একটি কোডবেস অডিট করার সময়, একটি বাগ উপস্থিত হতে পারে কিনা তা দেখতে সলিডিটি পৃষ্ঠায় প্রকাশের ঘোষণাগুলির বিপরীতে সলিডিটি সংস্করণটি পরীক্ষা করুন৷
স্মার্ট চুক্তিগুলি প্রক্সি প্যাটার্ন (বা খুব কমই, রূপান্তরিত প্যাটার্ন) দিয়ে আপগ্রেড করা যেতে পারে। স্মার্ট চুক্তিগুলি অপরিবর্তিত থাকার জন্য একটি নির্বিচারে স্মার্ট চুক্তির কার্যকারিতার উপর নির্ভর করা উচিত নয়।
দৃঢ়তা ফাংশন স্থানান্তর এবং প্রেরণ ব্যবহার করা উচিত নয়। তারা ইচ্ছাকৃতভাবে লেনদেনের সাথে ফরওয়ার্ড করা গ্যাসের পরিমাণ 2,300-এ সীমাবদ্ধ করে, যার ফলে বেশিরভাগ অপারেশন গ্যাস শেষ হয়ে যাবে।
সাধারণভাবে ব্যবহৃত জিনোসিস সেফ মাল্টি-সিগনেচার ওয়ালেট ফলব্যাক ফাংশনে কলটিকে অন্য ঠিকানায় ফরোয়ার্ড করা সমর্থন করে। যদি কেউ মাল্টিসিগ ওয়ালেটে ইথার পাঠাতে স্থানান্তর বা পাঠান ব্যবহার করে, তাহলে ফলব্যাক ফাংশন গ্যাস শেষ হয়ে যেতে পারে এবং স্থানান্তর ব্যর্থ হবে। gnosis নিরাপদ ফলব্যাক ফাংশনের একটি স্ক্রিনশট নীচে প্রদান করা হয়েছে৷ পাঠক স্পষ্টভাবে দেখতে পাচ্ছেন যে 2300 গ্যাস ব্যবহার করার জন্য যথেষ্ট অপারেশন রয়েছে।
আপনি যদি একটি চুক্তির সাথে যোগাযোগ করতে চান যা স্থানান্তর এবং প্রেরণ ব্যবহার করে, তাহলে Ethereum অ্যাক্সেস তালিকা লেনদেনের বিষয়ে আমাদের নিবন্ধটি দেখুন যা আপনাকে স্টোরেজ এবং চুক্তি অ্যাক্সেস অপারেশনগুলির গ্যাস খরচ কমাতে দেয়।
সলিডিটি 0.8.0 ওভারফ্লো এবং আন্ডারফ্লো সুরক্ষার মধ্যে তৈরি করেছে। সুতরাং যদি একটি আনচেক করা ব্লক উপস্থিত না থাকে, বা Yul-এ নিম্ন স্তরের কোড ব্যবহার না করা হয়, ওভারফ্লো হওয়ার কোনও আশঙ্কা নেই৷ যেমন, সেফম্যাথ লাইব্রেরিগুলি ব্যবহার করা উচিত নয় কারণ তারা অতিরিক্ত চেকগুলিতে গ্যাস নষ্ট করে।
কিছু সাহিত্য নথি যে ব্লক.টাইমস্ট্যাম্প একটি দুর্বলতা ভেক্টর কারণ খনি শ্রমিকরা এটি পরিচালনা করতে পারে। এটি সাধারণত এলোমেলোতার উত্স হিসাবে টাইমস্ট্যাম্প ব্যবহার করার ক্ষেত্রে প্রযোজ্য, যা পূর্বে নথিভুক্ত হিসাবে করা উচিত নয়। মার্জ-পরবর্তী Ethereum ঠিক 12 সেকেন্ডের (বা 12 সেকেন্ডের গুণিতক) ব্যবধানে টাইমস্ট্যাম্প আপডেট করে। যাইহোক, দ্বিতীয় স্তরের গ্রানুলারিটিতে সময় পরিমাপ করা একটি বিরোধী প্যাটার্ন। এক মিনিটের স্কেলে, যদি কোনো যাচাইকারী তাদের ব্লক স্লট মিস করে এবং ব্লক উৎপাদনে 24 সেকেন্ডের ব্যবধান ঘটে তাহলে ত্রুটির যথেষ্ট সুযোগ রয়েছে।
কোণার কেসগুলিকে সহজে সংজ্ঞায়িত করা যায় না, তবে একবার আপনি সেগুলির যথেষ্ট পরিমাণ দেখেছেন, আপনি তাদের জন্য একটি অন্তর্দৃষ্টি তৈরি করতে শুরু করেন। একটি কর্নার কেস এমন কিছু হতে পারে যেমন কেউ একটি পুরষ্কার দাবি করার চেষ্টা করছে, কিন্তু কিছুই আটকে নেই৷ এটি বৈধ, আমাদের কেবল তাদের শূন্য পুরস্কার দেওয়া উচিত। একইভাবে, আমরা সাধারণত পুরষ্কারগুলিকে সমানভাবে ভাগ করতে চাই, কিন্তু শুধুমাত্র একজন প্রাপক থাকলে এবং প্রযুক্তিগতভাবে কোনো বিভাজন না হলে কী হবে?
এই উদাহরণটি অক্ষয় শ্রীবাস্তবের টুইটার থ্রেড থেকে নেওয়া হয়েছে এবং সংশোধন করা হয়েছে।
কেসটি বিবেচনা করুন যেখানে কেউ একটি বিশেষাধিকারপ্রাপ্ত অ্যাকশন পরিচালনা করতে পারে যদি বিশেষাধিকারপ্রাপ্ত ঠিকানাগুলির একটি সেট এটির জন্য একটি স্বাক্ষর প্রদান করে।
contract VulnerableMultisigAuthorization { struct Authorization { bytes signature; address authorizer; bytes32 hashOfAction; // more fields } // more codef unction takeAction(Authorization[] calldata auths, bytes calldata action) public { // logic for avoiding replay attacks for (uint256 i; i < auths.length; ++i) { require(validateSignature(auths[i].signature, auths[i].authorizer), "invalid signature"); require(authorizers[auths[i].authorizer], "address is not an authorizer"); } doTheAction(action) } }
যদি কোনো স্বাক্ষর বৈধ না হয়, বা স্বাক্ষর একটি বৈধ ঠিকানার সাথে মেলে না, তাহলে প্রত্যাবর্তন ঘটবে। কিন্তু যদি অ্যারে খালি হয়? সেক্ষেত্রে, এটি কোনো স্বাক্ষরের প্রয়োজন ছাড়াই সম্পূর্ণভাবে doTheAction-এ চলে যাবে।
contract ProportionalRewards { mapping(address => uint256) originalId; address[] stakers; function stake(uint256 id) public { nft.transferFrom(msg.sender, address(this), id); stakers.append(msg.sender); } function unstake(uint256 id) public { require(originalId[id] == msg.sender, "not the owner"); removeFromArray(msg.sender, stakers); sendRewards(msg.sender, totalRewardsSinceLastclaim() / stakers.length()); nft.transferFrom(address(this), msg.sender, id); } }
যদিও উপরের কোডটি সমস্ত ফাংশন বাস্তবায়ন দেখায় না, এমনকি যদি ফাংশনগুলি তাদের নামের বর্ণনা অনুসারে আচরণ করে, তবুও একটি বাগ রয়েছে। আপনি এটা চিহ্নিত করতে পারেন? নিচে স্ক্রোল করার আগে উত্তর না দেখার জন্য আপনাকে কিছু জায়গা দেওয়ার জন্য এখানে একটি ছবি রয়েছে।
removeFromArray এবং sendRewards ফাংশন ভুল ক্রমে আছে। স্টেকারস অ্যারেতে শুধুমাত্র একজন ব্যবহারকারী থাকলে, শূন্য ত্রুটি দ্বারা বিভাজন হবে এবং ব্যবহারকারী তাদের NFT প্রত্যাহার করতে পারবেন না। অধিকন্তু, পুরষ্কারগুলি সম্ভবত লেখকের ইচ্ছামত ভাগ করা হয় না। যদি মূল চারটি স্টেকার থাকে, এবং একজন ব্যক্তি প্রত্যাহার করে, তবে প্রত্যাহারের সময় অ্যারের দৈর্ঘ্য 3 হওয়ায় সে পুরস্কারের এক তৃতীয়াংশ পাবে।
আসুন একটি বাস্তব উদাহরণ ব্যবহার করি যে কিছু অনুমান দ্বারা $100 মিলিয়ন ডলারের বেশি ক্ষতি হয়েছে। আপনি যদি যৌগিক প্রোটোকল সম্পূর্ণরূপে না বুঝেন তবে চিন্তা করবেন না, আমরা শুধুমাত্র প্রাসঙ্গিক অংশগুলিতে ফোকাস করব। (এছাড়াও যৌগিক প্রোটোকল হল DeFi-এর ইতিহাসে সবচেয়ে গুরুত্বপূর্ণ এবং ফলপ্রসূ প্রোটোকলগুলির মধ্যে একটি, আমরা এটি আমাদের DeFi বুটক্যাম্পে শেখাই, তাই এটি যদি প্রোটোকলের আপনার প্রথম ধারণা হয়, বিপথগামী হবেন না)।
যাইহোক, কম্পাউন্ডের বিন্দু হল ব্যবহারকারীদের তাদের নিষ্ক্রিয় ক্রিপ্টোকারেন্সি ধার দেওয়ার জন্য পুরস্কৃত করা অন্যান্য ব্যবসায়ীদের যাদের এটির জন্য একটি ব্যবহার থাকতে পারে। ঋণদাতাদের সুদ এবং COMP টোকেন উভয় ক্ষেত্রেই অর্থ প্রদান করা হয় (ঋণগ্রহীতারা একটি COMP টোকেন পুরস্কার দাবি করতে পারে, কিন্তু আমরা এখনই তাতে ফোকাস করব না)।
কম্পাউন্ড কম্পট্রোলার হল একটি প্রক্সি চুক্তি যা কম্পাউন্ড গভর্ন্যান্স দ্বারা সেট করা যেতে পারে এমন বাস্তবায়নের জন্য কল অর্পণ করে।
30 সেপ্টেম্বর, 2021-এ গভর্নেন্স প্রস্তাব 62- এ, বাস্তবায়ন চুক্তিটি একটি বাস্তবায়ন চুক্তিতে সেট করা হয়েছিল যার দুর্বলতা ছিল। একই দিন এটি লাইভ হয়েছিল, টুইটারে দেখা গেছে যে কিছু লেনদেন শূন্য টোকেন স্টক করা সত্ত্বেও COMP পুরস্কার দাবি করছে।
দুর্বল ফাংশন distributeSupplierComp()
এখানে মূল কোড
/** * @notice Calculate COMP accrued by a supplier and possibly transfer it to them * @param cToken The market in which the supplier is interacting * @param supplier The address of the supplier to distribute COMP to */ function distributeSupplierComp(address cToken, address supplier) internal { // TODO: Don't distribute supplier COMP if the user is not in the supplier market. // This check should be as gas efficient as possible as distributeSupplierComp is called in many places. // - We really don't want to call an external contract as that's quite expensive. CompMarketState storage supplyState = compSupplyState[cToken]; uint supplyIndex = supplyState.index; uint supplierIndex = compSupplierIndex[cToken][supplier]; // Update supplier's index to the current index since we are distributing accrued COMP compSupplierIndex[cToken][supplier] = supplyIndex; if (supplierIndex == 0 && supplyIndex > compInitialIndex) { // Covers the case where users supplied tokens before the market's supply state index was set. // Rewards the user with COMP accrued from the start of when supplier rewards were first // set for the market. supplierIndex = compInitialIndex; } // Calculate change in the cumulative sum of the COMP per cToken accrued Double memory deltaIndex = Double({mantissa: sub_(supplyIndex, supplierIndex)}); uint supplierTokens = CToken(cToken).balanceOf(supplier); // Calculate COMP accrued: cTokenAmount * accruedPerCToken uint supplierDelta = mul_(supplierTokens, deltaIndex); uint supplierAccrued = add_(compAccrued[supplier], supplierDelta); compAccrued[supplier] = supplierAccrued; emit DistributedSupplierComp(CToken(cToken), supplier, supplierDelta, supplyIndex); }
বাগ, পরিহাস, TODO মন্তব্যে আছে. "ব্যবহারকারী সরবরাহকারী বাজারে না থাকলে সরবরাহকারী COMP বিতরণ করবেন না।" কিন্তু এর জন্য কোডে কোনো চেক নেই। যতক্ষণ ব্যবহারকারী তাদের ওয়ালেটে স্টেকিং টোকেন রাখেন (CToken(cToken).balanceOf(সরবরাহকারী);), তারপর
প্রস্তাবনা 64 9 অক্টোবর, 2021-এ বাগ সংশোধন করেছে।
যদিও এটি একটি ইনপুট বৈধতা বাগ বলে যুক্তি দেওয়া যেতে পারে, ব্যবহারকারীরা দূষিত কিছু জমা দেননি। যদি কেউ কিছু না রাখার জন্য পুরস্কার দাবি করার চেষ্টা করে, তাহলে সঠিক গণনা শূন্য হওয়া উচিত। যুক্তিযুক্তভাবে, এটি একটি ব্যবসায়িক যুক্তি বা কর্নার কেস ত্রুটি বেশি।
ডিফাই হ্যাক যা বাস্তব জগতে ঘটে প্রায়শই উপরের সুন্দর বিভাগগুলির মধ্যে পড়ে না।
প্যারিটি ওয়ালেটটি সরাসরি ব্যবহার করার উদ্দেশ্যে ছিল না। এটি একটি রেফারেন্স বাস্তবায়ন যা স্মার্ট চুক্তির ক্লোনগুলি নির্দেশ করবে। বাস্তবায়নের জন্য ক্লোনগুলিকে ইচ্ছা হলে স্ব-ধ্বংস করার অনুমতি দেওয়া হয়েছিল, তবে এর জন্য সমস্ত ওয়ালেট মালিকদের এটিতে সাইন অফ করতে হবে৷
// throw unless the contract is not yet initialized.modifier only_uninitialized { if (m_numOwners > 0) throw; _; } function initWallet(address[] _owners, uint _required, uint _daylimit) only_uninitialized { initDaylimit(_daylimit); initMultiowned(_owners, _required); }
মানিব্যাগ মালিকদের ঘোষণা করা হয়
// kills the contract sending everything to `_to`.function kill(address _to) onlymanyowners(sha3(msg.data)) external { suicide(_to); }
কিছু সাহিত্য এটিকে একটি "অরক্ষিত আত্মধ্বংস" অর্থাৎ অ্যাক্সেস নিয়ন্ত্রণ ব্যর্থতা হিসাবে বর্ণনা করে, তবে এটি পুরোপুরি সঠিক নয়। সমস্যাটি ছিল যে initWallet ফাংশনটি বাস্তবায়ন চুক্তিতে কল করা হয়নি এবং এটি কাউকে নিজেরাই initWallet ফাংশনকে কল করার এবং নিজেদের মালিক বানানোর অনুমতি দেয়। এটি তাদের কিল ফাংশন কল করার ক্ষমতা দিয়েছে। এর মূল কারণ ছিল বাস্তবায়ন শুরু করা হয়নি। অতএব, ত্রুটিপূর্ণ সলিডিটি কোডের কারণে নয়, একটি ত্রুটিপূর্ণ স্থাপনার প্রক্রিয়ার কারণে বাগটি চালু করা হয়েছিল।
এই হ্যাকটিতে কোন সলিডিটি কোড ব্যবহার করা হয়নি। পরিবর্তে, আক্রমণকারীরা ক্লাউডফ্লেয়ার এপিআই কী পায় এবং ওয়েবসাইট ফ্রন্টএন্ডে একটি স্ক্রিপ্ট ইনজেকশন করে যা আক্রমণকারীর ঠিকানায় সরাসরি প্রত্যাহারের জন্য ব্যবহারকারীর লেনদেন পরিবর্তন করে। এই নিবন্ধে আরো পড়ুন.
অনেকগুলি অগ্রণী শূন্য সহ ঠিকানাগুলি আবিষ্কার করার প্রেরণা হল যে তারা ব্যবহার করার জন্য আরও বেশি গ্যাস দক্ষ। একটি Ethereum লেনদেন লেনদেনের ডেটাতে একটি শূন্য বাইটের জন্য 4 গ্যাস এবং একটি নন-জিরো বাইটের জন্য 16 গ্যাস চার্জ করা হয়।
যেমন, উইন্টারমিউট হ্যাক করা হয়েছিল কারণ এটি অশ্লীল ঠিকানা ব্যবহার করেছে ( লিখতে )। এখানে 1 ইঞ্চি লেখা আছে কিভাবে অশ্লীলতা ঠিকানা জেনারেটর আপস করা হয়েছিল।
এই নিবন্ধে ট্রাস্ট ওয়ালেটের একটি অনুরূপ দুর্বলতা নথিভুক্ত ছিল ( https://blog.ledger.com/Funds-of-every-wallet-created-with-the-Trust-Wallet-browser-extension-could-have-been- চুরি/ )
মনে রাখবেন যে এটি তৈরি 2-তে লবণ পরিবর্তন করে আবিষ্কৃত অগ্রণী শূন্য সহ স্মার্ট চুক্তিতে প্রযোজ্য নয়, কারণ স্মার্ট চুক্তিতে ব্যক্তিগত কী থাকে না।
উপবৃত্তাকার বক্ররেখা স্বাক্ষরের "r" এবং "s" বিন্দুটি নিম্নরূপ তৈরি করা হয়েছে
r = k * G (mod N) s = k^-1 * (h + r * privateKey) (mod N)
G, r, s, h, an N সবই সর্বজনীনভাবে পরিচিত। যদি "k" সর্বজনীন হয়ে যায়, তাহলে "privateKey" হল একমাত্র অজানা পরিবর্তনশীল, এবং এর সমাধান করা যেতে পারে। এই কারণে ওয়ালেটগুলিকে পুরোপুরি এলোমেলোভাবে k তৈরি করতে হবে এবং এটি পুনরায় ব্যবহার করবেন না। যদি এলোমেলোতা পুরোপুরি এলোমেলো না হয়, তাহলে k অনুমান করা যেতে পারে।
জাভা লাইব্রেরিতে অনিরাপদ র্যান্ডমনেস জেনারেশন 2013 সালে অনেক অ্যান্ড্রয়েড বিটকয়েন ওয়ালেটকে দুর্বল করে রেখেছিল। (বিটকয়েন ইথেরিয়ামের মতো একই স্বাক্ষর অ্যালগরিদম ব্যবহার করে।)
এই তালিকার অ্যান্টি-প্যাটার্নগুলিকে দ্রুত চিনতে নিজেকে প্রশিক্ষিত করা আপনাকে আরও কার্যকর স্মার্ট কন্ট্রাক্ট প্রোগ্রামার করে তুলবে, কিন্তু বেশিরভাগ স্মার্ট কন্ট্রাক্ট বাগগুলি উদ্দিষ্ট ব্যবসায়িক যুক্তি এবং কোডটি আসলে কী করে তার মধ্যে অমিলের কারণে।
স্মার্ট কন্ট্রাক্ট ইউনিট টেস্টিং হল স্মার্ট কন্ট্রাক্টের জন্য সবচেয়ে মৌলিক সুরক্ষা, কিন্তু স্মার্ট কন্ট্রাক্টের একটি চমকপ্রদ সংখ্যক হয় সেগুলির অভাব রয়েছে বা পর্যাপ্ত পরীক্ষার কভারেজ নেই।
কিন্তু ইউনিট পরীক্ষা শুধুমাত্র চুক্তির "সুখী পথ" (প্রত্যাশিত/পরিকল্পিত আচরণ) পরীক্ষা করে। আশ্চর্যজনক ক্ষেত্রে পরীক্ষা করার জন্য, অতিরিক্ত পরীক্ষার পদ্ধতি প্রয়োগ করতে হবে।
যারা এখানকার কিছু পদ্ধতির সাথে অপরিচিত তাদের জন্য, সাইফ্রিন অডিটসের প্যাট্রিক কলিন্স তার ভিডিওতে স্টেটফুল এবং স্টেটলেস ফাজিংয়ের একটি হাস্যকর ভূমিকা রেখেছেন।
এই কাজগুলি সম্পন্ন করার সরঞ্জামগুলি দ্রুত আরও বিস্তৃত এবং ব্যবহার করা সহজ হয়ে উঠছে।
কিছু লেখক এই Repos এ পূর্ববর্তী DeFi হ্যাকগুলির একটি তালিকা সংকলন করেছেন:
নিরাপত্তা অধ্যয়ন এবং অনুশীলন করার জন্য সিকিউরিয়াম ব্যাপকভাবে ব্যবহৃত হয়েছে, কিন্তু মনে রাখবেন রেপো 2 বছর ধরে উল্লেখযোগ্যভাবে আপডেট করা হয়নি
আপনি আমাদের সলিডিটি রিডলস ভান্ডারের সাথে দৃঢ়তার দুর্বলতাগুলিকে কাজে লাগানোর অনুশীলন করতে পারেন।
DamnVulnerableDeFi হল একটি ক্লাসিক ওয়ারগেম যা প্রত্যেক ডেভেলপারের অনুশীলন করা উচিত
ক্যাপচার দ্য ইথার এবং ইথারনট ক্লাসিক, তবে মনে রাখবেন কিছু সমস্যা অবাস্তবভাবে সহজ বা পুরানো সলিডিটি ধারণা শেখান
কিছু স্বনামধন্য ক্রাউডসোর্সড সিকিউরিটি ফার্মের কাছে অধ্যয়নের জন্য অতীতের অডিটের একটি দরকারী তালিকা রয়েছে।
আপনি যদি সলিডিটিতে সাবলীল না হন, তাহলে আপনি Ethereum স্মার্ট চুক্তিগুলি অডিট করতে পারবেন এমন কোনও উপায় নেই৷
স্মার্ট কন্ট্রাক্ট অডিটর হওয়ার জন্য কোনো শিল্প স্বীকৃত সার্টিফিকেশন নেই। যে কেউ একটি ওয়েবসাইট এবং সোশ্যাল মিডিয়া প্রোফাইল তৈরি করতে পারে এবং নিজেকে সলিটি অডিটর বলে দাবি করতে পারে এবং পরিষেবা বিক্রি শুরু করতে পারে এবং অনেকেই তা করেছে৷ অতএব, সতর্কতা অবলম্বন করুন এবং নিয়োগের আগে রেফারেল পান।
একজন স্মার্ট কন্ট্রাক্ট অডিটর হওয়ার জন্য, আপনাকে বাগ খুঁজে বের করার ক্ষেত্রে গড় সলিডিটি ডেভেলপারের থেকে যথেষ্ট ভালো হতে হবে। যেমন, একজন অডিটর হওয়ার জন্য "রোডম্যাপ" মাস এবং মাসের নিরলস এবং ইচ্ছাকৃত অনুশীলন ছাড়া আর কিছুই নয় যতক্ষণ না আপনি বেশিরভাগের চেয়ে ভাল স্মার্ট কন্ট্রাক্ট বাগ ক্যাচার হন।
দুর্বলতা শনাক্ত করার ক্ষেত্রে আপনার সমবয়সীদের ছাড়িয়ে যাওয়ার দৃঢ় সংকল্পের অভাব থাকলে, উচ্চ প্রশিক্ষিত এবং অনুপ্রাণিত অপরাধীদের আগে আপনি জটিল সমস্যাগুলি খুঁজে পাবেন না।
স্মার্ট কন্ট্রাক্ট অডিটিং সম্প্রতি এটি লাভজনক এই উপলব্ধির কারণে কাজ করার জন্য একটি পছন্দসই ক্ষেত্র হিসাবে বিবেচিত হয়েছে। প্রকৃতপক্ষে, কিছু বাগ বাউন্টি পেআউট 1 মিলিয়ন ডলার ছাড়িয়ে গেছে, তবে এটি অত্যন্ত বিরল ব্যতিক্রম, আদর্শ নয়।
Code4rena তাদের অডিট প্রতিযোগিতায় প্রতিযোগীদের কাছ থেকে পেআউটের একটি পাবলিক লিডারবোর্ড রয়েছে, যা আমাদের সাফল্যের হার সম্পর্কে কিছু তথ্য দেয়।
বোর্ডে এখনও 1171 জনের নাম রয়েছে
এটিও বিবেচনা করুন, যখন ওপেনজেপেলিন একটি নিরাপত্তা গবেষণা ফেলোশিপের জন্য একটি আবেদন খোলেন (কোনও চাকরি নয়, একটি প্রাক-চাকরি স্ক্রীনিং এবং প্রশিক্ষণ), তারা 300 টিরও বেশি আবেদন পেয়েছিল শুধুমাত্র 10 জনেরও কম প্রার্থীকে বেছে নেওয়ার জন্য, যার মধ্যে খুব কম পূর্ণ পাবে। সময় কাজ
এটি হার্ভার্ডের তুলনায় কম ভর্তির হার।
স্মার্ট চুক্তি নিরীক্ষা একটি প্রতিযোগিতামূলক শূন্য-সমষ্টি খেলা। অডিট করার জন্য শুধুমাত্র এতগুলি প্রকল্প আছে, নিরাপত্তার জন্য শুধুমাত্র এত বাজেট, এবং শুধুমাত্র অনেকগুলি বাগ খুঁজে পাওয়া যায়। আপনি যদি এখনই নিরাপত্তা অধ্যয়ন করা শুরু করেন, সেখানে ডজন ডজন অত্যন্ত অনুপ্রাণিত ব্যক্তি এবং দল রয়েছে যাদের আপনার উপর একটি বিশাল হেডস্টার্ট রয়েছে। বেশীরভাগ প্রজেক্ট একটি অপরীক্ষিত নতুন নিরীক্ষকের পরিবর্তে একটি খ্যাতি সহ একটি অডিটরের জন্য একটি প্রিমিয়াম দিতে ইচ্ছুক।
এই নিবন্ধে, আমরা দুর্বলতার অন্তত 20টি বিভিন্ন বিভাগ তালিকাভুক্ত করেছি। আপনি যদি প্রত্যেককে আয়ত্ত করতে এক সপ্তাহ ব্যয় করেন (যা কিছুটা আশাবাদী), আপনি কেবল অভিজ্ঞ নিরীক্ষকদের কাছে সাধারণ জ্ঞান কী তা বুঝতে শুরু করছেন। আমরা এই নিবন্ধে গ্যাস অপ্টিমাইজেশান বা টোকেনমিক্স কভার করিনি, উভয়ই একজন নিরীক্ষকের বোঝার জন্য গুরুত্বপূর্ণ বিষয়। গণিত করুন এবং আপনি দেখতে পাবেন এটি একটি ছোট যাত্রা নয়।
যে বলে, সম্প্রদায়টি সাধারণত বন্ধুত্বপূর্ণ এবং নতুনদের জন্য সহায়ক এবং টিপস এবং কৌশল প্রচুর। কিন্তু যারা স্মার্ট কন্ট্রাক্ট সিকিউরিটি থেকে ক্যারিয়ার গড়ার আশায় এই আর্টিকেলটি পড়ছেন, তাদের জন্য এটা পরিষ্কারভাবে বোঝা গুরুত্বপূর্ণ যে লাভজনক ক্যারিয়ার পাওয়ার সম্ভাবনা আপনার পক্ষে নয়। সাফল্য ডিফল্ট ফলাফল নয়।
এটি অবশ্যই করা যেতে পারে , এবং বেশ কিছু লোক অডিটিংয়ে একটি লাভজনক ক্যারিয়ারের জন্য কোন সলিডিটি না জানা থেকে চলে গেছে। আইন স্কুলে ভর্তি হওয়া এবং বার পরীক্ষায় উত্তীর্ণ হওয়ার চেয়ে দুই বছরের সময়ের মধ্যে স্মার্ট কন্ট্রাক্ট অডিটর হিসাবে চাকরি পাওয়া যুক্তিযুক্তভাবে সহজ। অন্যান্য ক্যারিয়ার পছন্দের তুলনায় এটি অবশ্যই আরও উল্টোদিকে রয়েছে।
তবে তা সত্ত্বেও আপনার সামনে দ্রুত বিকশিত জ্ঞানের পর্বতকে আয়ত্ত করতে এবং বাগ খুঁজে বের করার জন্য আপনার অন্তর্দৃষ্টিকে উন্নত করতে আপনার পক্ষ থেকে অত্যন্ত কঠিন অধ্যবসায়ের প্রয়োজন হবে।
এটি বলার অপেক্ষা রাখে না যে স্মার্ট চুক্তি নিরাপত্তা শেখা একটি সার্থক সাধনা নয়। এটা একেবারে হয়. কিন্তু আপনি যদি আপনার চোখে ডলারের চিহ্ন নিয়ে মাঠের দিকে আসছেন, তাহলে আপনার প্রত্যাশাগুলোকে নিয়ন্ত্রণে রাখুন।
পরিচিত বিরোধী প্যাটার্ন সম্পর্কে সচেতন হওয়া গুরুত্বপূর্ণ। যাইহোক, বেশিরভাগ বাস্তব-বিশ্বের বাগগুলি অ্যাপ্লিকেশন নির্দিষ্ট। উভয় শ্রেণীর দুর্বলতা সনাক্ত করার জন্য ক্রমাগত এবং ইচ্ছাকৃত অনুশীলন প্রয়োজন।
আমাদের শিল্প-নেতৃস্থানীয় দৃঢ়তা প্রশিক্ষণের সাথে স্মার্ট চুক্তি নিরাপত্তা, এবং আরও অনেক Ethereum উন্নয়ন বিষয় শিখুন।
এই নিবন্ধটির প্রধান চিত্রটি হ্যাকারনুনেরএআই ইমেজ জেনারেটর দ্বারা "কম্পিউটারকে রক্ষাকারী একটি রোবট" প্রম্পটের মাধ্যমে তৈরি করা হয়েছে।