智能合约 硬编码私钥(Hardcoded Private Key)

技术博客 (128) 2023-10-25 09:01:01

攻击解释

硬编码私钥(Hardcoded Private Key):合约中硬编码的私钥可能被攻击者发现和滥用,导致资金被窃取。开发者应避免在合约中明文存储私钥或其他敏感信息。

漏洞代码

pragma solidity ^0.8.0;

contract HardcodedPrivateKey {
    mapping(address => uint256) private balances;

    constructor() {
        balances[msg.sender] = 1000;
    }

    function transfer(address to, uint256 amount) public {
        require(balances[msg.sender] >= amount, "Insufficient balance");
        balances[msg.sender] -= amount;
        balances[to] += amount;
    }

    function checkBalance(address account) public view returns (uint256) {
        // 使用硬编码的私钥访问其他账户余额
        require(msg.sender == 0x1234567890, "Unauthorized");
        return balances[account];
    }
}

合约解释:

在这个合约中,有一个名为 HardcodedPrivateKey 的合约,包含了一个存储账户余额的映射 balances。在构造函数中,合约将部署者的账户余额初始化为 1000。

合约提供了 transfer 函数用于转账,并使用 balances 映射来记录账户余额的变化。另外,合约还提供了 checkBalance 函数,用于查询账户余额。

然而,这个合约存在 Hardcoded Private Key 的风险。在 checkBalance 函数中,通过硬编码的方式,将合约的所有者的地址(0x1234567890)与 msg.sender 进行比较,以限制只有合约所有者能够访问其他账户的余额。

由于私钥硬编码在合约中,攻击者可以轻易地发现并使用相同的私钥,从而绕过访问控制,获取其他账户的余额信息。

为了修复 Hardcoded Private Key 攻击,开发者应避免在合约中明文存储私钥或其他敏感信息。合约应采用更安全的身份验证机制,如基于权限控制的访问控制修饰符(如 onlyOwner),或使用外部账户签名来验证访问权限。

攻击方法

pragma solidity ^0.8.0;

contract HardcodedPrivateKeyAttack {
    HardcodedPrivateKey public targetContract;
    
    constructor(HardcodedPrivateKey _targetContract) {
        targetContract = HardcodedPrivateKey(_targetContract);
    }

    function attack() public view returns (uint256) {
        // 调用目标合约的 checkBalance 函数,绕过访问控制
        return targetContract.checkBalance(address(this));
    }
}

合约解释:

在这个攻击合约中,我们使用了一个名为 HardcodedPrivateKeyAttack 的合约来攻击 HardcodedPrivateKey 合约。在构造函数中,我们传入了目标合约的实例地址 _targetContract

攻击的核心是 attack 函数。在这个函数中,我们直接调用目标合约的 checkBalance 函数,并传递当前攻击合约的地址作为参数。由于私钥被硬编码在目标合约中,并且攻击者使用了相同的私钥,所以访问控制条件 require(msg.sender == 0x1234567890, "Unauthorized") 将会通过验证。

通过执行这个攻击合约中的 attack 函数,攻击者可以成功调用 HardcodedPrivateKey 合约的 checkBalance 函数,并获取其他账户的余额信息。

修复方法

pragma solidity ^0.8.0;

contract HardcodedPrivateKeyFixed {
    mapping(address => uint256) private balances;
    address private owner;

    constructor() {
        owner = msg.sender;
        balances[owner] = 1000;
    }

    function transfer(address to, uint256 amount) public {
        require(balances[msg.sender] >= amount, "Insufficient balance");
        balances[msg.sender] -= amount;
        balances[to] += amount;
    }

    function checkBalance(address account) public view returns (uint256) {
        require(msg.sender == owner || msg.sender == account, "Unauthorized");
        return balances[account];
    }
}

合约解析

在修复后的合约中,我们对 checkBalance 函数进行了改进。在访问控制条件中,我们使用逻辑运算符 || 来同时验证合约的所有者和访问者的身份。

通过 require(msg.sender == owner || msg.sender == account, "Unauthorized"),我们要求只有合约的所有者或账户持有者才能够访问账户余额。这样,除了合约所有者,其他人无法绕过访问控制获取他人的余额信息。

通过这种修复,我们有效地防止了 Hardcoded Private Key 攻击,确保只有合约所有者和账户持有者才能够访问相关的账户余额信息。开发者应避免在合约中明文存储私钥或其他敏感信息,并采取适当的权限控制机制,以确保合约和用户的安全。

THE END

发表回复