
Solidity सुरक्षा
यह पोस्ट एक अपेक्षाकृत गहन और अद्यतन परिचयात्मक पोस्ट होने का प्रयास करती है, जिसमें Solidity डेवलपर्स द्वारा की गई पिछली गलतियों का विवरण दिया गया है, ताकि भविष्य के डेवलपर्स इतिहास को दोहराने से बच सकें।
Ethereum स्मार्ट कॉन्ट्रैक्ट्स की एक विशेषता अन्य बाहरी कॉन्ट्रैक्ट्स के कोड को कॉल करने और उपयोग करने की क्षमता है। कॉन्ट्रैक्ट्स आमतौर पर ether को भी संभालते हैं, और इस तरह अक्सर विभिन्न बाहरी उपयोगकर्ता एड्रेसों पर ether भेजते हैं। बाहरी कॉन्ट्रैक्ट्स को कॉल करने, या किसी एड्रेस पर ether भेजने के लिए कॉन्ट्रैक्ट द्वारा एक बाहरी कॉल किया जाना आवश्यक है। इन बाहरी कॉल्स को हमलावरों द्वारा हाईजैक किया जा सकता है, जिससे वे कॉन्ट्रैक्ट को आगे का कोड निष्पादित करने के लिए मजबूर करते हैं (अर्थात फॉलबैक फ़ंक्शन के माध्यम से) , जिसमें स्वयं के भीतर वापस कॉल करना शामिल है। इस प्रकार कोड निष्पादन कॉन्ट्रैक्ट में "पुनः-प्रवेश" करता है। इस प्रकार के हमलों का उपयोग कुख्यात DAO हैक में किया गया था।
री-एंट्रेंसी हमलों पर अधिक पढ़ने के लिए, देखें स्मार्ट कॉन्ट्रैक्ट्स पर री-एंट्रेंसी हमला और Consensus - Ethereum स्मार्ट कॉन्ट्रैक्ट सर्वोत्तम अभ्यास.
यह हमला तब हो सकता है जब कोई कॉन्ट्रैक्ट किसी अज्ञात एड्रेस पर ether भेजता है। एक हमलावर किसी बाहरी एड्रेस पर सावधानीपूर्वक एक ऐसा कॉन्ट्रैक्ट बना सकता है जिसमें फॉलबैक फ़ंक्शन में दुर्भावनापूर्ण कोड हो। इस प्रकार, जब कोई कॉन्ट्रैक्ट इस एड्रेस पर ether भेजता है, तो यह दुर्भावनापूर्ण कोड को लागू करेगा। आमतौर पर दुर्भावनापूर्ण कोड कमज़ोर कॉन्ट्रैक्ट पर एक फ़ंक्शन निष्पादित करता है, जो डेवलपर द्वारा अपेक्षित नहीं किए गए ऑपरेशन करता है। "री-एंट्रेंसी" नाम इस तथ्य से आया है कि बाहरी दुर्भावनापूर्ण कॉन्ट्रैक्ट कमज़ोर कॉन्ट्रैक्ट पर एक फ़ंक्शन को वापस कॉल करता है और कमज़ोर कॉन्ट्रैक्ट पर एक मनमाने स्थान पर कोड निष्पादन में "पुनः-प्रवेश" करता है।
इसे स्पष्ट करने के लिए, सरल कमज़ोर कॉन्ट्रैक्ट पर विचार करें, जो एक Ethereum तिजोरी के रूप में कार्य करता है जो जमाकर्ताओं को प्रति सप्ताह केवल 1 ether निकालने की अनुमति देता है।
EtherStore.sol:```solidity contract EtherStore {
uint256 public withdrawalLimit = 1 ether;
mapping(address => uint256) public lastWithdrawTime;
mapping(address => uint256) public balances;
function depositFunds() public payable {
balances[msg.sender] += msg.value;
}
function withdrawFunds (uint256 _weiToWithdraw) public {
require(balances[msg.sender] >= _weiToWithdraw);
// limit the withdrawal
require(_weiToWithdraw <= withdrawalLimit);
// limit the time allowed to withdraw
require(now >= lastWithdrawTime[msg.sender] + 1 weeks);
require(msg.sender.call.value(_weiToWithdraw)());
balances[msg.sender] -= _weiToWithdraw;
lastWithdrawTime[msg.sender] = now;
}
}
यह कॉन्ट्रैक्ट दो सार्वजनिक फ़ंक्शन रखता है। `depositFunds()` और `withdrawFunds()`। `depositFunds()` फ़ंक्शन केवल भेजने वाले के बैलेंस को बढ़ाता है। `withdrawFunds()` फ़ंक्शन भेजने वाले को निकालने के लिए wei की राशि निर्दिष्ट करने की अनुमति देता है। यह केवल तभी सफल होगा जब निकालने के लिए अनुरोधित राशि 1 ether से कम हो और पिछले सप्ताह में कोई निकासी न हुई हो। या ऐसा है?...
संवेदनशीलता \[17\] पंक्ति पर आती है जहाँ हम उपयोगकर्ता को उनकी अनुरोधित ether की राशि भेजते हैं। एक दुर्भावनापूर्ण हमलावर पर विचार करें जो निम्नलिखित कॉन्ट्रैक्ट बनाता है,
Attack.sol:```solidity
import "EtherStore.sol";
contract Attack {
EtherStore public etherStore;