当前位置: 首页 > article >正文

智能合约安全指南 [特殊字符]️

智能合约安全指南 🛡️

在这里插入图片描述

1. 安全基础

1.1 常见漏洞类型

  1. 重入攻击
  2. 整数溢出
  3. 权限控制缺陷
  4. 随机数漏洞
  5. 前后运行攻击
  6. 签名重放

1.2 安全开发原则

  1. 最小权限原则
  2. 检查-生效-交互模式
  3. 状态机安全
  4. 失败保护机制

2. 重入攻击防护

2.1 基本防护模式

contract ReentrancyGuarded {
    bool private locked;
    
    modifier noReentrant() {
        require(!locked, "Reentrant call");
        locked = true;
        _;
        locked = false;
    }
    
    function withdraw() external noReentrant {
        uint256 amount = balances[msg.sender];
        require(amount > 0, "No balance");
        
        balances[msg.sender] = 0; // 先更新状态
        
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success, "Transfer failed");
    }
}

2.2 检查-生效-交互模式

contract CEIPattern {
    mapping(address => uint256) private balances;
    
    function deposit() external payable {
        balances[msg.sender] += msg.value;
    }
    
    function withdraw(uint256 amount) external {
        // 检查
        require(balances[msg.sender] >= amount, "Insufficient balance");
        
        // 生效
        balances[msg.sender] -= amount;
        
        // 交互
        (bool success, ) = msg.sender.call{value: amount}("");
        require(success, "Transfer failed");
    }
}

3. 访问控制

3.1 角色管理

contract RoleBasedAccess {
    using EnumerableSet for EnumerableSet.AddressSet;
    
    mapping(bytes32 => EnumerableSet.AddressSet) private roles;
    
    event RoleGranted(bytes32 indexed role, address indexed account);
    event RoleRevoked(bytes32 indexed role, address indexed account);
    
    modifier onlyRole(bytes32 role) {
        require(hasRole(role, msg.sender), "Unauthorized");
        _;
    }
    
    function hasRole(
        bytes32 role,
        address account
    ) public view returns (bool) {
        return roles[role].contains(account);
    }
    
    function grantRole(
        bytes32 role,
        address account
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (roles[role].add(account)) {
            emit RoleGranted(role, account);
        }
    }
    
    function revokeRole(
        bytes32 role,
        address account
    ) external onlyRole(DEFAULT_ADMIN_ROLE) {
        if (roles[role].remove(account)) {
            emit RoleRevoked(role, account);
        }
    }
}

3.2 权限代理

contract DelegatedAccess {
    mapping(address => mapping(address => bool)) private delegates;
    
    event DelegateChanged(
        address indexed delegator,
        address indexed delegatee,
        bool status
    );
    
    function setDelegate(address delegatee, bool status) external {
        delegates[msg.sender][delegatee] = status;
        emit DelegateChanged(msg.sender, delegatee, status);
    }
    
    function isDelegate(
        address delegator,
        address delegatee
    ) public view returns (bool) {
        return delegates[delegator][delegatee];
    }
    
    modifier onlyDelegateOrOwner(address owner) {
        require(
            msg.sender == owner || isDelegate(owner, msg.sender),
            "Not authorized"
        );
        _;
    }
}

4. 数据验证

4.1 输入验证

contract InputValidation {
    uint256 public constant MAX_ARRAY_LENGTH = 100;
    uint256 public constant MAX_VALUE = 1e20;
    
    function validateArrayInput(uint256[] calldata data) internal pure {
        require(data.length > 0, "Empty array");
        require(data.length <= MAX_ARRAY_LENGTH, "Array too long");
        
        for (uint i = 0; i < data.length; i++) {
            require(data[i] <= MAX_VALUE, "Value too large");
            if (i > 0) {
                require(data[i] >= data[i-1], "Not sorted");
            }
        }
    }
    
    function validateAddress(address addr) internal pure {
        require(addr != address(0), "Zero address");
        require(addr.code.length == 0, "Contract address not allowed");
    }
}

4.2 状态验证

contract StateValidation {
    enum State { Inactive, Active, Paused, Ended }
    State public currentState;
    
    modifier inState(State requiredState) {
        require(currentState == requiredState, "Invalid state");
        _;
    }
    
    function validateTransition(State newState) internal view {
        if (currentState == State.Inactive) {
            require(newState == State.Active, "Invalid transition");
        } else if (currentState == State.Active) {
            require(
                newState == State.Paused || newState == State.Ended,
                "Invalid transition"
            );
        }
    }
}

5. 签名验证

5.1 EIP712 签名

contract EIP712Verifier {
    bytes32 private DOMAIN_SEPARATOR;
    
    struct EIP712Domain {
        string name;
        string version;
        uint256 chainId;
        address verifyingContract;
    }
    
    constructor(string memory name, string memory version) {
        DOMAIN_SEPARATOR = keccak256(
            abi.encode(
                keccak256(
                    "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
                ),
                keccak256(bytes(name)),
                keccak256(bytes(version)),
                block.chainid,
                address(this)
            )
        );
    }
    
    function verifySignature(
        bytes32 hash,
        bytes memory signature
    ) internal view returns (address) {
        bytes32 digest = keccak256(
            abi.encodePacked("\x19\x01", DOMAIN_SEPARATOR, hash)
        );
        return ecrecover(digest, signature[0], signature[1], signature[2]);
    }
}

5.2 签名重放防护

contract ReplayProtection {
    mapping(bytes32 => bool) private usedSignatures;
    
    function isSignatureUsed(bytes32 hash) public view returns (bool) {
        return usedSignatures[hash];
    }
    
    function markSignatureAsUsed(bytes32 hash) internal {
        require(!usedSignatures[hash], "Signature already used");
        usedSignatures[hash] = true;
    }
    
    function validateSignature(
        bytes32 hash,
        bytes memory signature,
        uint256 deadline
    ) internal view returns (address) {
        require(block.timestamp <= deadline, "Signature expired");
        require(!isSignatureUsed(hash), "Signature already used");
        
        return verifySignature(hash, signature);
    }
}

6. 紧急响应

6.1 紧急停止

contract EmergencyStop {
    bool public stopped;
    address public guardian;
    
    modifier whenNotStopped() {
        require(!stopped, "Contract is stopped");
        _;
    }
    
    modifier whenStopped() {
        require(stopped, "Contract is not stopped");
        _;
    }
    
    function toggleStop() external {
        require(msg.sender == guardian, "Not authorized");
        stopped = !stopped;
        emit EmergencyToggled(stopped);
    }
    
    function emergencyWithdraw() external whenStopped {
        require(msg.sender == guardian, "Not authorized");
        // 执行紧急提款逻辑
    }
}

6.2 漏洞修复

contract UpgradeableSecurityFix {
    address public implementation;
    address public admin;
    
    function upgrade(address newImplementation) external {
        require(msg.sender == admin, "Not authorized");
        require(newImplementation.code.length > 0, "Not a contract");
        
        // 验证新实现是否兼容
        require(
            IUpgradeable(newImplementation).supportsInterface(0x01ffc9a7),
            "Incompatible implementation"
        );
        
        implementation = newImplementation;
        emit Upgraded(newImplementation);
    }
}

7. 审计和测试

7.1 自动化测试

const { expect } = require("chai");
const { ethers } = require("hardhat");

describe("SecurityTests", function() {
    let contract;
    let owner;
    let attacker;
    
    beforeEach(async function() {
        const Contract = await ethers.getContractFactory("SecureContract");
        [owner, attacker] = await ethers.getSigners();
        contract = await Contract.deploy();
    });
    
    it("Should prevent reentrancy attacks", async function() {
        await expect(
            contract.connect(attacker).withdraw()
        ).to.be.revertedWith("Reentrant call");
    });
    
    it("Should validate access control", async function() {
        await expect(
            contract.connect(attacker).adminFunction()
        ).to.be.revertedWith("Not authorized");
    });
});

7.2 形式化验证

/// @notice Invariant: total supply should always equal sum of balances
/// @custom:invariant totalSupply == sum(balances)
contract VerifiedToken {
    mapping(address => uint256) public balances;
    uint256 public totalSupply;
    
    function transfer(address to, uint256 amount) external {
        require(balances[msg.sender] >= amount, "Insufficient balance");
        
        balances[msg.sender] -= amount;
        balances[to] += amount;
        
        assert(balances[msg.sender] <= totalSupply);
        assert(balances[to] <= totalSupply);
    }
}

8. 相关资源

  • 智能合约安全最佳实践
  • OpenZeppelin 安全博客
  • 以太坊安全工具集
  • Slither 静态分析工具
  • MythX 安全平台

http://www.kler.cn/a/571651.html

相关文章:

  • 强化学习-随机近似与随机梯度下降
  • SQL注入练习场:PHPStudy+SQLI-LABS靶场搭建教程(零基础友好版)
  • 爬虫不“刑”教程
  • 航天科技民用化破局:凡拓数创以数字孪生重塑智能制造基因
  • AMD RDNA3 GPU架构解析
  • Visual Studio 2022 安装指南
  • GitLab 密钥详解:如何安全地使用 SSH 密钥进行身份验证
  • 颠覆NLP的魔法:深度解读Transformer架构及其核心组件
  • 如何安装配置Goland并使用固定公网地址SSH远程连接本地服务器
  • 【金融量化】Ptrade中的基础交易与高级量化交易策略的下单接口
  • 01. HarmonyOS应用开发实践与技术解析
  • DAV_postgresql_4-pg安装
  • 物联网小范围高精度GPS使用
  • TCP协议/HTTP协议
  • centOS 环境 安装redis方法
  • Python Web应用开发之Flask框架——基础
  • Windows平台调试器原理与编写04.硬件断点
  • mongodb,redis,hbase都是nosql数据库,其最大区别和不同定位是什么?redis为什么可以做到百万级QPS?
  • 使用300M带宽是否可以流畅地玩原神
  • CSS—隐藏元素:1分钟掌握与使用隐藏元素的方法