以太坊中由Owner问题引发的CVE漏洞
字数 1697 2025-08-22 12:22:36

以太坊智能合约Owner权限安全漏洞分析与防范指南

一、构造函数声明问题

1.1 历史背景与漏洞原理

在Solidity 0.4.22版本之前,构造函数使用合约名作为函数名进行声明,例如:

contract Owned {
    address public owner;
    
    function Owned() {
        owner = msg.sender;
    }
}

这种声明方式存在以下问题:

  • 容易因拼写错误导致构造函数失效
  • 构造函数变成普通可调用函数

1.2 新版本构造函数规范

Solidity 0.4.22引入了constructor()语法:

正确形式

constructor() public {
    owner = msg.sender;
}

错误形式

function constructor() public {
    owner = msg.sender;
}

1.3 版本兼容性问题

  • 0.4.22-0.4.23版本:function constructor()会被当作普通函数编译,不会报错
  • 0.4.23+版本:会产生警告但仍能编译
  • 最新版本:直接编译失败

1.4 防范措施

  1. 使用无function关键字的constructor()声明方式
  2. 使用最新版本Solidity编译器
  3. 不要忽略Remix等IDE的编译警告
  4. 部署前严格测试构造函数是否按预期执行

二、CVE-2018-11329案例分析

2.1 漏洞合约背景

Ether Cartel游戏合约(类似Ether Shrimp Farm)存在权限控制漏洞,允许任意用户修改合约所有者地址。

2.2 漏洞代码分析

// 漏洞代码片段
function DrugDealer() public {
    ceoAddress = msg.sender;
}

问题点:

  • 缺少权限修饰符(如onlyOwner
  • 函数名误导开发者以为是特殊函数
  • 允许任意用户调用并修改ceoAddress

2.3 攻击过程

  1. 攻击者调用DrugDealer()函数
  2. ceoAddress修改为攻击者地址
  3. 调用特权函数(如SellDrugs)窃取资金
function SellDrugs() public {
    // 转账逻辑,fee会转入ceoAddress
    uint256 fee = SafeMath.div(eth, dividendFee_);
    ceoAddress.transfer(fee);
}

2.4 时间线

  • 部署时间:2018年5月18日17:14:56 UTC
  • 被攻击时间:1小时11分钟后

2.5 防范措施

  1. 所有修改关键状态变量(特别是所有者地址)的函数必须添加权限控制
  2. 使用标准化的权限修饰符(如onlyOwner
  3. 避免使用可能产生误导的函数命名

三、CVE-2018-10705案例分析

3.1 漏洞合约概述

Aurora DAO (AURA)代币合约存在任意设置owner的漏洞。

3.2 漏洞代码分析

contract Owned {
    address public owner;
    
    function Owned() {
        owner = msg.sender;
    }
    
    function setOwner(address _owner) returns (bool success) {
        owner = _owner;
        return true;
    }
    
    modifier onlyOwner {
        require(msg.sender == owner);
        _;
    }
}

问题点:

  • setOwner函数缺少onlyOwner修饰符
  • 允许任意用户修改合约所有者

3.3 特权函数示例

function unlockToken() onlyOwner {
    locked = false;
}

function uploadBalances(address[] recipients, uint256[] balances) onlyOwner {
    // 批量修改用户余额
}

function lockBalances() onlyOwner {
    balancesUploaded = true;
}

3.4 攻击影响

  1. 攻击者调用setOwner成为新owner
  2. 调用unlockToken()解除转账限制
  3. 通过uploadBalances任意修改余额
  4. 转移合约资金

3.5 防范措施

  1. 所有修改owner的函数必须添加onlyOwner修饰符
  2. 关键管理函数应实现多签机制
  3. 考虑使用OpenZeppelin的Ownable合约作为基础

四、综合防范建议

4.1 编码规范

  1. 构造函数

    • 使用constructor()语法
    • 避免使用function关键字
    • 初始化所有关键状态变量
  2. 权限控制

    • 为所有管理函数添加权限修饰符
    • 使用标准化修饰符(如onlyOwner
    • 考虑实现角色分级(如admin、operator等)
  3. 函数命名

    • 避免使用可能产生误导的函数名
    • 管理函数使用明确的前缀(如admin_

4.2 开发实践

  1. 编译器使用

    • 使用最新稳定版Solidity编译器
    • 启用所有编译警告并视为错误
    • 设置合理的pragma版本(如^0.8.0
  2. 测试策略

    • 单元测试覆盖所有权限相关功能
    • 测试非特权用户调用管理函数的情况
    • 使用静态分析工具(如Slither)
  3. 代码审计

    • 部署前进行专业安全审计
    • 特别检查所有状态变量修改点
    • 验证继承合约的权限控制

4.3 合约架构建议

  1. 使用经过验证的权限控制库(如OpenZeppelin)
  2. 实现权限转移的延迟机制(如时间锁)
  3. 考虑将关键功能模块化并分离权限
  4. 为关键操作实现事件日志和监控

五、参考资源

  1. Solidity官方文档 - 构造函数
  2. OpenZeppelin合约库
  3. Ether Cartel合约地址
  4. 智能合约安全验证工具Slither

通过系统性地应用这些防范措施,开发者可以显著降低智能合约中与Owner权限相关的安全风险,保护合约资产和用户利益。

以太坊智能合约Owner权限安全漏洞分析与防范指南 一、构造函数声明问题 1.1 历史背景与漏洞原理 在Solidity 0.4.22版本之前,构造函数使用合约名作为函数名进行声明,例如: 这种声明方式存在以下问题: 容易因拼写错误导致构造函数失效 构造函数变成普通可调用函数 1.2 新版本构造函数规范 Solidity 0.4.22引入了 constructor() 语法: 正确形式 : 错误形式 : 1.3 版本兼容性问题 0.4.22-0.4.23版本: function constructor() 会被当作普通函数编译,不会报错 0.4.23+版本:会产生警告但仍能编译 最新版本:直接编译失败 1.4 防范措施 使用无 function 关键字的 constructor() 声明方式 使用最新版本Solidity编译器 不要忽略Remix等IDE的编译警告 部署前严格测试构造函数是否按预期执行 二、CVE-2018-11329案例分析 2.1 漏洞合约背景 Ether Cartel游戏合约(类似Ether Shrimp Farm)存在权限控制漏洞,允许任意用户修改合约所有者地址。 2.2 漏洞代码分析 问题点: 缺少权限修饰符(如 onlyOwner ) 函数名误导开发者以为是特殊函数 允许任意用户调用并修改 ceoAddress 2.3 攻击过程 攻击者调用 DrugDealer() 函数 将 ceoAddress 修改为攻击者地址 调用特权函数(如 SellDrugs )窃取资金 2.4 时间线 部署时间:2018年5月18日17:14:56 UTC 被攻击时间:1小时11分钟后 2.5 防范措施 所有修改关键状态变量(特别是所有者地址)的函数必须添加权限控制 使用标准化的权限修饰符(如 onlyOwner ) 避免使用可能产生误导的函数命名 三、CVE-2018-10705案例分析 3.1 漏洞合约概述 Aurora DAO (AURA)代币合约存在任意设置owner的漏洞。 3.2 漏洞代码分析 问题点: setOwner 函数缺少 onlyOwner 修饰符 允许任意用户修改合约所有者 3.3 特权函数示例 3.4 攻击影响 攻击者调用 setOwner 成为新owner 调用 unlockToken() 解除转账限制 通过 uploadBalances 任意修改余额 转移合约资金 3.5 防范措施 所有修改owner的函数必须添加 onlyOwner 修饰符 关键管理函数应实现多签机制 考虑使用OpenZeppelin的Ownable合约作为基础 四、综合防范建议 4.1 编码规范 构造函数 : 使用 constructor() 语法 避免使用 function 关键字 初始化所有关键状态变量 权限控制 : 为所有管理函数添加权限修饰符 使用标准化修饰符(如 onlyOwner ) 考虑实现角色分级(如admin、operator等) 函数命名 : 避免使用可能产生误导的函数名 管理函数使用明确的前缀(如 admin_ ) 4.2 开发实践 编译器使用 : 使用最新稳定版Solidity编译器 启用所有编译警告并视为错误 设置合理的pragma版本(如 ^0.8.0 ) 测试策略 : 单元测试覆盖所有权限相关功能 测试非特权用户调用管理函数的情况 使用静态分析工具(如Slither) 代码审计 : 部署前进行专业安全审计 特别检查所有状态变量修改点 验证继承合约的权限控制 4.3 合约架构建议 使用经过验证的权限控制库(如OpenZeppelin) 实现权限转移的延迟机制(如时间锁) 考虑将关键功能模块化并分离权限 为关键操作实现事件日志和监控 五、参考资源 Solidity官方文档 - 构造函数 OpenZeppelin合约库 Ether Cartel合约地址 智能合约安全验证工具Slither 通过系统性地应用这些防范措施,开发者可以显著降低智能合约中与Owner权限相关的安全风险,保护合约资产和用户利益。