solidity-security-best-practices

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Solidity Security Best Practices

Solidity智能合约安全最佳实践

When to Apply

适用场景

  • Reviewing smart contract code for common vulnerabilities.
  • Implementing critical patterns like Checks-Effects-Interactions.
  • Auditing access control and upgradeability logic.
  • Preparing for a security audit or bug bounty.
  • Debugging unexpected behavior in external contract interactions.
  • 检查智能合约代码中的常见漏洞。
  • 实现Checks-Effects-Interactions(CEI)等关键模式。
  • 审计访问控制与可升级性逻辑。
  • 为安全审计或漏洞赏金活动做准备。
  • 调试外部合约交互中的异常行为。

Critical Security Patterns

核心安全模式

Checks-Effects-Interactions (CEI)

Checks-Effects-Interactions(CEI)模式

Always update state variables before making external calls to prevent reentrancy.
solidity
// BAD
function withdraw(uint amount) public {
    require(balances[msg.sender] >= amount);
    (bool s, ) = msg.sender.call{value: amount}("");
    balances[msg.sender] -= amount;
}
solidity
// GOOD
function withdraw(uint amount) public {
    require(balances[msg.sender] >= amount);
    balances[msg.sender] -= amount;
    (bool s, ) = msg.sender.call{value: amount}("");
    require(s);
}
在进行外部调用前务必先更新状态变量,以防止重入攻击。
solidity
// BAD
function withdraw(uint amount) public {
    require(balances[msg.sender] >= amount);
    (bool s, ) = msg.sender.call{value: amount}("");
    balances[msg.sender] -= amount;
}
solidity
// GOOD
function withdraw(uint amount) public {
    require(balances[msg.sender] >= amount);
    balances[msg.sender] -= amount;
    (bool s, ) = msg.sender.call{value: amount}("");
    require(s);
}

Access Control

访问控制

Restrict sensitive functions to authorized addresses using standard patterns.
solidity
// BAD
function setOwner(address _new) public {
    owner = _new;
}
solidity
// GOOD
function setOwner(address _new) public onlyOwner {
    owner = _new;
}
使用标准模式将敏感函数限制为仅授权地址可调用。
solidity
// BAD
function setOwner(address _new) public {
    owner = _new;
}
solidity
// GOOD
function setOwner(address _new) public onlyOwner {
    owner = _new;
}

Reentrancy Protection

重入防护

Use mutexes to prevent recursive calls into the same function or contract.
solidity
// BAD
function claim() public {
    require(!claimed[msg.sender]);
    msg.sender.call{value: 1 ether}("");
    claimed[msg.sender] = true;
}
solidity
// GOOD
function claim() public nonReentrant {
    require(!claimed[msg.sender]);
    claimed[msg.sender] = true;
    payable(msg.sender).transfer(1 ether);
}
使用互斥锁防止对同一函数或合约的递归调用。
solidity
// BAD
function claim() public {
    require(!claimed[msg.sender]);
    msg.sender.call{value: 1 ether}("");
    claimed[msg.sender] = true;
}
solidity
// GOOD
function claim() public nonReentrant {
    require(!claimed[msg.sender]);
    claimed[msg.sender] = true;
    payable(msg.sender).transfer(1 ether);
}

Safe External Calls

安全外部调用

Handle token transfer failures and validate external contract interactions.
solidity
// BAD
function pay(IERC20 token, uint amount) public {
    token.transfer(msg.sender, amount);
}
solidity
// GOOD
using SafeERC20 for IERC20;
function pay(IERC20 token, uint amount) public {
    token.safeTransfer(msg.sender, amount);
}
处理代币转账失败情况并验证外部合约交互。
solidity
// BAD
function pay(IERC20 token, uint amount) public {
    token.transfer(msg.sender, amount);
}
solidity
// GOOD
using SafeERC20 for IERC20;
function pay(IERC20 token, uint amount) public {
    token.safeTransfer(msg.sender, amount);
}

High Priority Patterns

高优先级模式

Input Validation

输入验证

Sanitize all user-provided data to prevent unexpected state changes.
solidity
// BAD
function setRate(uint _rate) public {
    rate = _rate;
}
solidity
// GOOD
function setRate(uint _rate) public {
    if (_rate == 0) revert InvalidRate();
    rate = _rate;
}
对所有用户提供的数据进行清理,以防止意外的状态变更。
solidity
// BAD
function setRate(uint _rate) public {
    rate = _rate;
}
solidity
// GOOD
function setRate(uint _rate) public {
    if (_rate == 0) revert InvalidRate();
    rate = _rate;
}

Upgrade Safety

升级安全性

Protect implementation contracts and ensure storage compatibility.
solidity
// BAD
contract MyProxy is Initializable {
    uint public x;
    function init(uint _x) public { x = _x; }
}
solidity
// GOOD
contract MyProxy is Initializable {
    uint public x;
    function init(uint _x) public initializer { x = _x; }
}
保护实现合约并确保存储兼容性。
solidity
// BAD
contract MyProxy is Initializable {
    uint public x;
    function init(uint _x) public { x = _x; }
}
solidity
// GOOD
contract MyProxy is Initializable {
    uint public x;
    function init(uint _x) public initializer { x = _x; }
}

Circuit Breakers

断路器机制

Implement emergency stop mechanisms to pause functionality during attacks.
solidity
// BAD
function trade() public {
    _performTrade();
}
solidity
// GOOD
function trade() public whenNotPaused {
    _performTrade();
}
实现紧急停止机制,以便在攻击期间暂停功能。
solidity
// BAD
function trade() public {
    _performTrade();
}
solidity
// GOOD
function trade() public whenNotPaused {
    _performTrade();
}

Medium Priority Patterns

中优先级模式

Signature Security

签名安全

Prevent replay attacks by including nonces and domain separators.
solidity
// BAD
function exec(bytes memory sig) public {
    address signer = recover(sig);
    _doWork(signer);
}
solidity
// GOOD
function exec(bytes memory sig, uint nonce) public {
    require(!used[nonce]);
    used[nonce] = true;
    address signer = recover(sig, nonce);
}
通过包含随机数(nonce)和域分隔符防止重放攻击。
solidity
// BAD
function exec(bytes memory sig) public {
    address signer = recover(sig);
    _doWork(signer);
}
solidity
// GOOD
function exec(bytes memory sig, uint nonce) public {
    require(!used[nonce]);
    used[nonce] = true;
    address signer = recover(sig, nonce);
}

Randomness

随机性实现

Avoid using on-chain data for randomness; use verifiable random functions.
solidity
// BAD
uint rand = uint(keccak256(abi.encodePacked(block.timestamp)));
solidity
// GOOD
// Use Chainlink VRF
uint rand = IVRF(vrf).requestRandomWords();
避免使用链上数据生成随机性;使用可验证随机函数。
solidity
// BAD
uint rand = uint(keccak256(abi.encodePacked(block.timestamp)));
solidity
// GOOD
// Use Chainlink VRF
uint rand = IVRF(vrf).requestRandomWords();

Event Emission

事件触发

Emit events for all significant state changes to facilitate off-chain tracking.
solidity
// BAD
function update(uint _v) public {
    val = _v;
}
solidity
// GOOD
function update(uint _v) public {
    val = _v;
    emit Updated(_v);
}
对所有重要的状态变更触发事件,以便于链下追踪。
solidity
// BAD
function update(uint _v) public {
    val = _v;
}
solidity
// GOOD
function update(uint _v) public {
    val = _v;
    emit Updated(_v);
}

Common Vulnerability Checklist

常见漏洞检查表

Vulnerability NameSCWE IDQuick Fix
tx.origin AuthenticationSCWE-018Use msg.sender instead
Unprotected SELFDESTRUCTSCWE-038Add access control to selfdestruct
Reentrancy - External Call Before State UpdateSCWE-046Use CEI pattern or ReentrancyGuard
Unchecked External Call Return ValueSCWE-109Use require() or SafeERC20
Delegatecall InjectionSCWE-132Validate target address for delegatecall
Integer Overflow/UnderflowSCWE-106Use Solidity 0.8+ or SafeMath
Default Function VisibilitySCWE-128Explicitly define visibility
Unencrypted On-Chain Private DataSCWE-136Encrypt data or store off-chain
Weak RandomnessSCWE-015Use Chainlink VRF or commit-reveal
Unprotected Ether WithdrawalSCWE-029Add access control to withdrawal
Uninitialized Storage PointerSCWE-043Initialize all storage pointers
Signature Replay AttackSCWE-020Use nonces and EIP-712
Hash Collision with abi.encodePackedSCWE-025Use abi.encode for dynamic types
DoS with Block Gas LimitSCWE-031Avoid loops over unbounded arrays
Floating PragmaSCWE-058Lock pragma to a specific version
Front-RunningSCWE-063Use commit-reveal or slippage protection
Unprotected InitializerSCWE-053Use 'initializer' modifier
Incorrect Access ControlSCWE-048Use OpenZeppelin AccessControl/Ownable
DoS with Unexpected RevertSCWE-030Use pull-over-push for payments
Assert ViolationSCWE-067Use require() for input validation
Lack of Reentrancy GuardSCWE-077Add nonReentrant modifier
Forced Ether via Self-DestructSCWE-079Don't rely on address(this).balance
Hardcoded Gas AmountSCWE-100Avoid .transfer(), use .call()
漏洞名称SCWE ID快速修复方案
tx.origin身份验证SCWE-018使用msg.sender替代
未受保护的SELFDESTRUCTSCWE-038为selfdestruct添加访问控制
重入攻击 - 外部调用先于状态更新SCWE-046使用CEI模式或ReentrancyGuard
未检查外部调用返回值SCWE-109使用require()或SafeERC20
Delegatecall注入SCWE-132验证delegatecall的目标地址
整数溢出/下溢SCWE-106使用Solidity 0.8+版本或SafeMath
默认函数可见性SCWE-128显式定义函数可见性
链上未加密私有数据SCWE-136加密数据或存储在链下
弱随机性SCWE-015使用Chainlink VRF或提交-揭示方案
未受保护的以太币提取SCWE-029为提取功能添加访问控制
未初始化的存储指针SCWE-043初始化所有存储指针
签名重放攻击SCWE-020使用nonce和EIP-712
abi.encodePacked哈希碰撞SCWE-025对动态类型使用abi.encode
区块Gas限制导致的DoSSCWE-031避免遍历无界数组
浮动版本声明SCWE-058将pragma锁定到特定版本
抢先交易(Front-Running)SCWE-063使用提交-揭示方案或滑点保护
未受保护的初始化函数SCWE-053使用'initializer'修饰符
错误的访问控制SCWE-048使用OpenZeppelin AccessControl/Ownable
异常回滚导致的DoSSCWE-030采用拉取式而非推送式支付
Assert断言违规SCWE-067使用require()进行输入验证
缺少重入防护SCWE-077添加nonReentrant修饰符
自毁强制转入以太币SCWE-079不要依赖address(this).balance
硬编码Gas值SCWE-100避免使用.transfer(),改用.call()

Enhanced with MCP

结合MCP增强功能

If you have the
solidity-agent-toolkit
MCP server configured, these tools provide automated security analysis:
  • run_slither
    for static analysis
  • match_vulnerability_patterns
    for heuristic detection
  • check_vulnerability
    for SCWE pattern matching
  • search_vulnerabilities
    for OWASP knowledge base lookup
如果你配置了
solidity-agent-toolkit
MCP服务器,这些工具可提供自动化安全分析:
  • run_slither
    :静态分析
  • match_vulnerability_patterns
    :启发式检测
  • check_vulnerability
    :SCWE模式匹配
  • search_vulnerabilities
    :OWASP知识库查询

References

参考资料

  • OWASP Smart Contract Top 10 (2026)
  • OWASP智能合约Top 10(2026版)