首页 > 百科 > pickcoin交易所里面的KCb能提到bfee交易所吗|区块链安全,要从设计抓起
链闻看天下  

pickcoin交易所里面的KCb能提到bfee交易所吗|区块链安全,要从设计抓起

摘要:文章来源:廖雪峰 作者:廖雪峰最近爆发的层出不穷的区块链安全问题,从以太坊 RPC 攻击转移用户资产,到 ERC20 代币频繁爆出溢出漏洞,这些问题其实大部分应

文章来源:廖雪峰
作者:廖雪峰

最近爆发的层出不穷的区块链安全问题,从以太坊 RPC 攻击转移用户资产,到 ERC20 代币频繁爆出溢出漏洞,这些问题其实大部分应该在区块链系统的设计阶段解决,而不是留给开发者来自己关注安全问题。

我们先来看一下以太坊的设计。

首先值得肯定的是,有别于比特币 UTXO 模型,以太坊设计了账户模型。账户模型对于实现智能合约是十分合理而且非常必要的,直接在 UTXO 模型上嫁接智能合约的做法显得不伦不类。

然而,以太坊的设计仍然存在不少问题,有许多设计问题实际上是引发安全漏洞的源头。如果在设计时避免了这些问题,至少不会大面积爆发各种安全问题。

RPC 安全

以太坊的一个重大安全缺陷是由 RPC 远程调用引起的。去年以来,黑客利用远程扫描工具或者植入木马,来尝试连接暴露在公网的以太坊节点,然后,不断尝试通过 sendTransaction 这个 RPC 把该节点的所有以太币转移到黑客的地址。

这个操作虽然需要私钥,然而黑客却可以绕开私钥,原因就在于用户正常发送交易时,无论是在钱包输入口令,还是通过 web3 的 JS,都间接调用了 geth 提供的 web3 的 unlockAccount 命令,这个命令一旦被用户触发,在接下来的一段时间内,黑客的 sendTransaction 无需私钥就能成功。并且,由于失败的 sendTransaction 不会被写入日志,用户几乎无法发现自己的全节点被黑客盯上了。如果黑客利用木马监听全节点的网络通信,完全可以通过 unlockAccount 获取用户口令,而以太坊的 RPC 是没有任何加密的。

这个安全漏洞实际上完全可以从设计避免。以太坊的钱包仿照了比特币钱包的设计,它实际上把全节点功能和钱包合二为一,用户私钥以加密形式保存在全节点中。中本聪最早设计的这种内置钱包的比特币全节点实际上是有严重安全问题的,但是,以太坊和大部分公链的开发者都照抄了这个设计。当用户进行正常转账时,钱包实际上和全节点的交互如下:

区块链安全,要从设计抓起

用户正常创建交易之前,需要调用 unlockAccount 来解锁私钥,然而,这个极其危险而重要的操作本质上是一个 RPC 调用。黑客能利用 sendTransaction 原因就在于,全节点不应该提供任何钱包的功能。全节点工作在 P2P 和共识层,而钱包工作在应用层,私钥理应由钱包管理,而不是全节点管理。

区块链安全,要从设计抓起

由钱包管理的加密私钥就不需要暴露在网络上,并且,从用户输入口令,创建交易,签名交易这一过程,根本不需要 RPC 调用,只有最后一步 sendRawTransaction 才需要 RPC 调用。sendRawTransaction 发送的是待广播的已签名交易,因此,这个数据被黑客截获是没有用的。

虽然比特币和以太坊的全节点提供了 disableWallet 这个选项来禁用私钥存储,但是问题在于,全节点根本就不应该提供存储私钥的功能。全节点也不应该提供 sendTransaction,全节点只能提供 sendRawTransaction。有个别公链居然只提供 sendTransaction 而不提供 sendRawTransaction,可见其工程实现的安全之差。

合约调用的容错性

以太坊的另一个重大漏洞允许任何用户进行 ERC20 的超额转账。该漏洞利用原理如下:

转移代币实际上就是调用 ERC20 合约的 transfer(address to, unit256 amount) 方法。该方法一共有两个参数:地址和数量。两个参数实际上都是 32 字节整数。调用该方法时,用户创建的 68 字节交易数据如下:

  • 4 字节方法哈希,总是 a9059cbb;
  • 32 字节以太坊地址,由于以太坊地址总是 20 字节,因此高位补 0,例如:000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca;
  • 32 字节代币数量,例如:00000000000000000000000000000000000000000000000000000000000000ff。

加在一起的交易数据就是:

a9059cbb
000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcabca
00000000000000000000000000000000000000000000000000000000000000ff

然而,以太坊的地址末尾如果是 0,用户输入的地址少于 20 字节时,以太坊会自动给它「补零」。利用以太坊虚拟机的这一「容错性」机制,可以创建一个恶意转账数据:

a9059cbb
000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcab
00000000000000000000000000000000000000000000000000000000000000ff

上述交易数据只有 67 字节,原因是地址末尾少了一个 0 字节。然而以太坊虚拟机并不会报错,转账也会成功。更令人惊奇的是,以太坊虚拟机从后面的参数「借」了一个 0,然后,在末尾自动补充 0,所以,实际参数变成了:

a9059cbb
000000000000000000000000abcabcabcabcabcabcabcabcabcabcabcabcab00
000000000000000000000000000000000000000000000000000000000000ff00

注意到 ff 后面的 0 是以太坊虚拟机自动补上的,这样一来,amount 从 ff 变成了 ff00,转账金额扩大了 256 倍。

通过计算一个末尾带 0 的地址,黑客就可以对交易所发起攻击。原理是交易所构造的转账交易是按 a9059cbb+用户提现地址+金额拼接而成。黑客先填写不足 20 字节的地址,如果交易所未检查地址长度,黑客通过申请一个 ff 金额的提现,实际到账金额是 ff00。

这个锅由以太坊虚拟机来背一点也不冤。检查非法输入是任何高级语言必须提供的基本功能。

Batch Overflow

最近爆出的 ERC20 代币的 Batch Overflow 漏洞看上去是开发者的问题:

function batchTransfer(address[] receivers, unit256 value) {
    unit256 amount = receivers.length * value
    require(value>0 && balances[msg.sender] >= amount)
    ...
}

漏洞代码在于计算总额 amount = receivers.length * value 时,输入一个非常大的 value 可能导致计算结果为负数,也就是整数计算溢出,从而导致后续转账成功,黑客凭空为自己转移出天量代币。

当然可以指责开发者没有编写出安全的代码,资深 Solidity 开发者还会说凡是涉及计算都应该使用 SafeMath 这个专为合约开发的计算库。SafeMath 会检查整数计算溢出,例如:

function add(uint256 a, uint256 b) {
    uint256 c = a + b;
    assert(c >= a);
    return c;
}

问题是,以太坊合约是一种非常高级的代码,虚拟机本身理应对所有整数运算自动检查溢出,而不是把责任推给开发者。没有任何人喜欢编写 c = add(a, b) 这样的代码。Java 虚拟机就通过禁用指针、数组索引检查、运行时类型检查等内置安全机制,有效提升了程序的健壮性。如果以太坊虚拟机内置了整数运算溢出检查,这个微小的工作就足以让 95% 的合约安全问题不复存在。

类似的问题还包括:合约没有真正的「所有者」,造成合约代码无法升级或者暂停。(目前的暂停机制也是合约逻辑的一部分,而不是以太坊合约机制的一部分)。新的智能合约公链应该在设计时尽量避免潜在的安全问题,从虚拟机上堵住恶意攻击,而不是一味教育开发者编写「安全」的代码。

Tags:
免责声明
世链财经作为开放的信息发布平台,所有资讯仅代表作者个人观点,与世链财经无关。如文章、图片、音频或视频出现侵权、违规及其他不当言论,请提供相关材料,发送到:2785592653@qq.com。
风险提示:本站所提供的资讯不代表任何投资暗示。投资有风险,入市须谨慎。
世链粉丝群:提供最新热点新闻,空投糖果、红包等福利,微信:juu3644。