Humanity Protocol 遭攻击事件:深入剖析 3600 万美元私钥灾难
事件概要
2026 年 6 月 9 日,主打掌纹扫描与零知识证明的去中心化身份项目 Humanity Protocol 遭遇重大安全漏洞。攻击者窃取了以太坊与 BNB 链上约 4.47 亿枚 H 代币,并在去中心化交易所抛售,导致代币价格在 12 小时内崩跌 80%–90%。实际损失超过 3000 万美元。
这并非复杂的智能合约漏洞,也不是闪电贷攻击或重入漏洞,而是一起私钥泄露事件,暴露了密钥管理、访问控制与运营安全的根本缺陷。
攻击步骤全解析
第一阶段:入侵点
攻击始于恶意软件感染某位开发人员的机器。该恶意软件取得 root 权限,并收集了本地存储的凭证与私钥。总计有七把私钥被窃:
- 一把热钱包私钥
- 三把 ETH Safe(多签)账户的私钥
- 三把 BSC Safe(多签)账户的私钥
这些私钥之所以会出现在该设备上,是因为项目在 2025 年 6 月主网上线时曾进行一次意外备份。一年的运营安全疏忽,在几秒钟内化为乌有。
第二阶段:热钱包失窃
攻击者取得热钱包私钥后,完全控制了该账户,并将 6,045,060 枚 H 代币从该钱包转移至自己的以太坊地址。
这是整个攻击中最简单、最直接的一步——无需多签、无需模拟交易,仅仅使用泄露的私钥进行一笔普通转账。
第三阶段:ETH Safe 漏洞利用
接着,攻击者利用窃取的多签密钥,离线构建了一笔针对 ETH Safe 账户的多签交易。该交易对项目的跨链桥合约进行了恶意升级。
此处的代码层面非常值得探讨。
代理合约 0x44f161ae29361e332dea039dfa2f404e0bc5b5cc 被升级为恶意实现合约(0xee1bd9356Fe66591F600d5769F3e0e03F012CaFa)。反编译该恶意实现后发现,其执行函数要求调用者地址必须是攻击者地址(0xd1ea823d421e0c829ee11f772af487fd352678ea)。
升级完成后,攻击者直接通过代理调用该恶意实现,将 141,182,632.22 枚 H 代币(价值约 1645 万美元)转移至其地址。
第四阶段:BSC Safe 漏洞利用
在 BNB Chain 上,攻击者采取了不同手法。他们提交了一笔交易,将 H 代币合约(0x44F161aE29361E332dEA039DFA2F404E0bC5B5Cc)的 ProxyAdmin 拥有者,从合法的 3/5 多签地址更改为攻击者地址(0x6Aa22CB8420E94Fc2119364b4c7885710aE753bB)。
取得拥有者权限后,攻击者升级了代币合约,并铸造了超过 4 亿枚 H 代币,随后在 DEX 上全数抛售。
代码层面的根本问题
问题一:中心化的升级权限
代理模式(EIP-1967)在 Web3 升级合约中相当常见,但此模式的安全性完全取决于谁能控制升级机制。
有漏洞的写法:
// 在 ProxyAdmin 合约中
contract ProxyAdmin {
address public owner;
function upgrade(address proxy, address implementation) external {
require(msg.sender == owner, "not owner");
// 将代理指向新的实现
}
}
在 Humanity Protocol 的案例中,ProxyAdmin 的拥有者是一个多签钱包。攻击者因窃取到足够的多签密钥,便能提交并执行一笔变更拥有者的交易,将拥有者改为自己,随后执行恶意升级。
修正方案:
contract ProxyAdmin {
// 使用时间锁控制器,而非直接拥有者
TimelockController public timelock;
function upgrade(address proxy, address implementation) external {
require(msg.sender == address(timelock), "only timelock");
// 升级代理
}
// 或实现 24–48 小时延迟,并搭配紧急暂停功能
mapping(bytes32 => uint256) public pendingUpgrades;
function proposeUpgrade(address proxy, address implementation) external {
require(msg.sender == owner, "not owner");
bytes32 hash = keccak256(abi.encodePacked(proxy, implementation));
pendingUpgrades[hash] = block.timestamp + 48 hours;
}
function executeUpgrade(address proxy, address implementation) external {
bytes32 hash = keccak256(abi.encodePacked(proxy, implementation));
require(pendingUpgrades[hash] != 0 && block.timestamp >= pendingUpgrades[hash], "too early");
// 执行升级
delete pendingUpgrades[hash];
}
}
为什么有效: 时间锁给予社区和安全监控者一段缓冲期,可在恶意升级提案被执行前侦测并应对。即使攻击者入侵多签钱包,也无法立即执行升级。
问题二:将多签密钥存储在同一台机器上
这是整起事件的根本原因。多签设计的前提是,不同密钥持有者应将各自密钥存储在不同的安全设备上。当所有密钥都备份到同一台开发者机器时,多签机制便形同虚设。
实际情况: ETH Safe 的三把密钥和 BSC Safe 的三把密钥(共六把多签密钥)全部存储在同一台开发者机器上,并在同一波恶意软件感染中全数泄露。
修正方案:
这不是代码层面的修正,而是运营安全的修正:
- 多签密钥必须存储在物理隔离的不同设备上
- 密钥绝不应备份到同一位置、云端存储或开发者机器
- 所有多签签署者均应使用硬件钱包
- 实施密钥轮换政策,并定期审查
- 绝不以明文存储私钥;应使用强密码短语进行加密存储
- 可考虑采用多方计算(MPC)钱包解决方案,此类方案从不存储完整私钥
问题三:链上升级缺乏验证
Humanity Protocol 合约中的代理升级机制,除了签名检查外,并未验证新实现是否安全或获得授权。
有漏洞的写法:
// 在代理合约中
function upgradeTo(address newImplementation) external {
require(msg.sender == admin, "only admin");
_setImplementation(newImplementation);
}
完全没有检查新实现的内容,也未要求实现必须经过验证或审计。
修正方案:
contract SecureProxy {
// 维护一个已核准实现的注册表
mapping(address => bool) public approvedImplementations;
address public registry;
function upgradeTo(address newImplementation) external {
require(msg.sender == admin, "only admin");
require(approvedImplementations[newImplementation] ||
IRegistry(registry).isApproved(newImplementation),
"implementation not approved");
_setImplementation(newImplementation);
}
// 实现应包含自我销毁防护
function _setImplementation(address newImplementation) internal {
// 检查该实现是否已被自毁
// 此处为简化写法,正式实现应采用 EIP-1967
require(newImplementation != address(0), "invalid implementation");
// 额外验证:检查实现是否支持特定接口
require(IImplementation(newImplementation).supportsInterface(type(IUpgradeable).interfaceId),
"invalid interface");
// 存储实现地址
assembly {
sstore(IMPLEMENTATION_SLOT, newImplementation)
}
}
}
为什么有效: 已核准实现注册表可确保仅有经过验证、审计的合约才能作为实现使用,防止攻击者部署恶意合约并将其设为实现。
问题四:缺乏事件监控与告警
攻击者执行热钱包转账、Safe 升级交易以及 BSC ProxyAdmin 所有权变更等操作,皆在数段时间内陆续完成。此期间完全没有触发任何告警,也没有监控系统侦测到这些异常交易。
修正方案:
- 针对所有管理函数(升级、所有权变更、铸币)实施实时监控
- 针对超过阈值的大额转账设置告警
- 监控代理合约是否有新的实现被设置
- 使用 Forta 或自定义监控机器人来侦测可疑模式
- 实现断路器机制,当侦测到异常时可暂停协议
contract PausableProxy {
bool public paused;
modifier whenNotPaused() {
require(!paused, "paused");
_;
}
function pause() external {
require(msg.sender == admin, "only admin");
paused = true;
emit Paused(msg.sender);
}
// 所有代理函数均应检查 whenNotPaused
}
人的问题:信任的集中化
Humanity Protocol 遭攻击事件揭示了根本真相:去中心化不仅是代码的事,更关乎运营安全与信任分布。
该协议在以太坊上设有 4/7 多签,在 BSC 上设有 3/5 多签。纸面上看似合理的去中心化,实际上所有密钥都存放在同一台机器上,使得多签机制沦为“安全剧场”而非实际保护。
ZachXBT 曾质疑这是否真的是意外,并暗示该事件其实是内鬼所为。无论是有意还是无意,结果都一样:私钥的集中化让这起事件成为可能。
给开发者的关键教训
1. 私钥绝非可有可无的安全控制项。 一旦你拥有私钥,就必须以最高安全等级对待。这意味着使用硬件钱包、气隙隔离机器,且绝不将私钥存放在恶意软件可访问的位置。
2. 多签的安全性取决于最弱的一环。 如果所有签署者都把密钥放在同一个地方,那么你拥有的不是多签,而是“多此一举的单点故障”。
3. 可升级性本身即是风险。 每个可升级合约都是潜在的攻击面。若非得使用可升级合约,请务必实现时间锁、核准注册表及严密监控。
4. 监控一切。 管理函数、大额转账、代理升级、所有权变更——这些都应触发告警,甚至自动暂停协议。
5. 去中心化运营,而不仅仅是代码。 区块链或许是去中心化的,但如果团队的运营安全是集中化的,协议依然脆弱。
结语
Humanity Protocol 遭攻击事件并非 Solidity 或智能合约设计的失败,而是运营安全的失败——开发者机器上存储了不该存储的私钥、多签并非真正的多签、升级机制过度信任权限检查。
代码本身没有问题,有问题的是流程。
身为开发者,我们花费大量时间审计智能合约、测试边界案例、优化 Gas。但若我们忽略运营安全——密钥如何存储、谁能访问、升级如何管理——那我们就是在沙滩上盖城堡。
三千六百万美元的问题不是“代码安全吗?”,而是“整个系统安全吗?”。
而对 Humanity Protocol 来说,答案显然是否定的。
网硕互联帮助中心





评论前必须登录!
注册