区块链安全和升级
最近以太坊Parity钱包发生15万个以太币被盗事件,比特币8月1日也面临着软硬分叉的选择。无论是漏洞还是版本升级引起的分叉,此时的区块链系统都面临着被攻击的危险。包括之前出现的DAO事件,交易所失窃事件,一系列的问题都让区块链参与者备受财务和精神损失。
据统计,即使是最安全的比特币区块链, 运行过程都大概出现了22次BUG,
软件系统产生问题不可避免,但如何让故障概率降到最小,同时在故障生产时如何快速隔离问题,这是每个区块链的设计和开发者需要认真考虑。
本文对历史上出现的重要一些漏洞进行案例分析,归纳出一些方法。比原链类似比特币采用UTXO和POW共识模型,又加入了图灵完备的智能合约系统,研究历史的教训对我们大有裨益, 当然也希望其他链的开发者在设计自己的区块链可以避免出现类似的漏洞,以及可以安全地进行版本升级。
比特币的交易数据结构是由很多脚本操作码构成的,攻击者可以设计多种交易结构类型使用这些操作码对节点进行拒绝服务攻击
比如0.3.5版本之前的比特币系统允许攻击者使用OP_LSHIFT脚本进行拒绝服务攻击。
switch (opcode)
......
case OP_LSHIFT:
if (bn2 < bnZero)
return false;
bn = bn1 << bn2.getulong();
break;
这是0.3.2版本中script.cpp中描述OP_LSHIFT的代码。OP_LSHIFT是一个数值运算的操作码,功能是bn2.getulong()左移bn1位并保留符号位得到bn。攻击者可能采用位运算让输出溢出的方式使CPU崩溃,从而达到拒绝服务攻击的效果。
if (opcode == OP_CAT ||
opcode == OP_SUBSTR ||
opcode == OP_LEFT ||
opcode == OP_RIGHT ||
opcode == OP_INVERT ||
opcode == OP_AND ||
opcode == OP_OR ||
opcode == OP_XOR ||
opcode == OP_2MUL ||
opcode == OP_2DIV ||
opcode == OP_MUL ||
opcode == OP_DIV ||
opcode == OP_MOD ||
opcode == OP_LSHIFT ||
opcode == OP_RSHIFT)
return false; // Disabled opcodes.
这是0.3.5以后版本中script.cpp描述OP_LSHIFT的代码。OP_LSHIFT已经直接被禁用。可以看到OP_LSHIFT等脚本操作码只是被禁用,并没有直接从代码里删除,如果想要重新启用这些脚本,就需要一次硬分叉。
另外,在#71036中区块发现了几个OP_CHECKSIG,这种命令会使节点做很多不必要的操作。
mTemplates.insert(make_pair(TX_PUBKEYHASH, CScript() << OP_DUP << OP_HASH160 << OP_PUBKEYHASH << OP_EQUALVERIFY << OP_CHECKSIG));
这是0.3.2版本中OP_CHECK是加密脚本,整个交易的输入、输出、脚本(从最近执行OP_CODESEPARATOR)都要哈希。所以当一个交易里面有几个OP_CHECKSIG的时候,会使