区块链安全—简单函数的危险漏洞(二)
字数 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:返回直接调用当前合约的地址(可能是合约地址)
多层调用实验:
- 合约A调用合约B调用合约C
- 在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);
}
}
攻击流程:
- 攻击者诱导用户向AttackContract转账
- 转账触发fallback函数
- fallback调用Phishable的withdrawAll
- 此时调用链:用户→AttackContract→Phishable
tx.origin是用户地址,通过require检查- 资金被转给攻击者
安全建议:
- 使用
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关键字 - 旧版本确保合约名与构造函数名完全一致
- 合约重命名时同步更新构造函数名
四、防御措施
-
构造函数安全:
- 使用Solidity 0.4.22+版本的
constructor语法 - 部署前严格检查合约名与构造函数名一致性
- 考虑使用初始化函数+权限控制替代构造函数敏感操作
- 使用Solidity 0.4.22+版本的
-
身份验证安全:
- 优先使用
msg.sender而非tx.origin - 必须使用
tx.origin时,确保理解其安全影响 - 结合其他验证机制如签名验证
- 优先使用
-
代码审计要点:
- 检查所有权限验证点的身份验证方式
- 验证构造函数定义的正确性
- 测试合约间调用的权限传递
五、总结
智能合约开发中,基础函数的安全使用至关重要。构造函数命名错误和tx.origin滥用是两类常见但危害严重的安全问题。开发者应:
- 严格遵循最新Solidity安全实践
- 理解
tx.origin与msg.sender的本质区别 - 对权限控制代码进行重点测试和审计
- 保持对合约基础安全问题的持续关注
通过系统性地理解和防范这些基础但关键的安全问题,可以显著提升智能合约的安全性和可靠性。