Solidity Security Essentials: Protect Your Smart Contracts
In blockchain development, security flaws aren’t just bugs—they’re catastrophic risks. A single vulnerability can lead to millions in losses. Let’s explore critical security practices for Solidity developers.
Why Security Matters
- πΈ Irreversible Losses: No "undo" button on blockchain
- π Immutable Code: Patches require redeployment
- π Public Attack Surface: Code is visible to all
Critical Vulnerabilities & Prevention
1. Reentrancy Attacks (The DAO Hack)
// Vulnerable Code
function withdraw() public {
uint balance = balances[msg.sender];
(bool success, ) = msg.sender.call{value: balance}("");
balances[msg.sender] = 0;
}
// Fixed with Checks-Effects-Interactions
function withdraw() public {
uint balance = balances[msg.sender];
balances[msg.sender] = 0; // Update first
(bool success, ) = msg.sender.call{value: balance}("");
}
2. Integer Overflow/Underflow
// Vulnerable
uint8 public count = 255;
count += 1; // Wraps to 0
// Protected (Solidity ≥0.8)
count += 1; // Auto-reverts
// For older versions:
using SafeMath for uint8;
count = count.add(1);
3. Access Control Issues
// Bad
function adminAction() public {
// No permission check
}
// Good
modifier onlyOwner() {
require(msg.sender == owner, "Unauthorized");
_;
}
function adminAction() public onlyOwner {}
⚠️ Dangerous Patterns
- Using
tx.origin
for auth - Unchecked low-level calls
- Public storage variables
Security Best Practices
Practice | Implementation |
---|---|
Input Validation | require(input != address(0)) |
Circuit Breakers | bool public paused = false; |
Rate Limiting | mapping(address => uint) lastAction; |
Essential Security Tools
- π‘️ Slither: Static analysis framework
- π MythX: Smart contract verification
- π OpenZeppelin: Audited contract libraries
Security Checklist
- ✅ Use latest Solidity version (≥0.8.20)
- ✅ Test with different ETH values
- ✅ Audit via multiple tools
- ✅ Implement time locks for critical changes
Your Security Challenge
Fix this vulnerable code:
contract Bank {
mapping(address => uint) balances;
function withdraw() public {
uint amount = balances[msg.sender];
(bool success, ) = msg.sender.call{value: amount}("");
balances[msg.sender] = 0;
}
}
Real-World Case Studies
- π The DAO Hack ($60M lost to reentrancy)
- π₯ Parity Wallet Freeze ($300M locked)
- π³️ BadgerDAO Frontend Attack ($120M stolen)
Comments
Post a Comment