安全路透社
当前位置:安全路透社 > 网络转载 > 正文

浅析互联网后最具颠覆性创新技术——区块链安全

* 本文原创作者:白泽安全团队

blockchain-linux-2.jpg

0×00 引言

近些年区块链呈现井喷式的速度被各行各业所垂青,在证券市场、支付系统、票据与供应链金融、客户征信与反欺诈等应用场景有很大的应用前景。在享有“互联网之后最具颠覆性的创新技术”之名的区块链技术应用背后的安全问题成为不可忽略的重要一环。本文简单介绍区块链并浅析区块链可能存在的安全问题。

0×01 区块链简介

1.1 区块链的起源

自1983年D.Chaum发表第一篇电子现金论文以来,在电子现金方面的研究一直没有间断过,直到中本聪在2008发表了“一个新的电子现金系统”的白皮书,2009年在一个开源的区块链上运行比特币才让区块链进入大家的视野。

2.png

说到区块链,大家都会联想到比特币、去中心化、智能合约、记账本、中本聪等关键词。简单来说,区块链就是一个去中心化的分布式账本,是比特币的底层技术。

1.2 区块链分类与特点

1.2.1 分类:公有链(例:比特币)、联盟链(例:R3CEV)、私有链(例:DAH)

  • 公有链:所有的机器都是在公开的网络上面,数量极其庞大,所以没有人能够控制这样的机器去达到个人的 目的,比特币就是一个典型公有链的例子。
  • 联盟链:由某个群体内部指定多个预选的节点为记账人,每个块的生成由所有的预选节点共同决定(预选节点参与共识过程),其他接入节点可以参与交易,但不过问记账过程,其他任何人可以通过该区块链开放的API进行限定查询。
  • 私有链:仅仅使用区块链的总账技术进行记账,可以是一个公司,也可以是个人,独享该区块链的写入权限,本链与其他的分布式存储方案没有太大区别。

1.2.2 特点:分布式(去中心化)、匿名性(无需信任)、开放性(高度透明)、加密安全性(不可篡改)

  • 去中心化:也就是说所有的交易都是点对点发生的,无需任何的信用中介或集中式清算机构;
  • 无需信任:任意两个节点间的数据交换无需互相信任,完全依靠区块链中的交易历史和数据的可追溯,以及共识机制来保证数据交换的正确且不可逆的执行。
  • 开放性:整个区块链网络中的数据是公开透明的,每个节点(参与者)都可自由加入该网络中,下载到所有的数据。
  • 加密安全性:跟当前银行网银系统(特别是公司网银系统)的加密机制类似,区块链的数据结构和交易流程中大量的使用了公私钥来加解密,保证数据的安全性。基于该技术基础,甚至可以应用群组签名来保证共有数据的安全性。另外区块链采取单向哈希算法,每个新产生的区块严格按照时间线形顺序推进,时间的不可逆性导致任何试图入侵篡改区块链内数据信息的行为都很容易被追溯,导致被其他节点的排斥,从而可以限制相关不法行为。

1.3 区块链工作流程

  1. 首先客户端发起一项交易后,会广播到网络中并等待确认
  2. 网络中的节点对收到的数据记录信息进行检验,比如记录信息是否合法。通过检验后,数据记录将被纳入到一个区块中;
  3. 全网所有接收节点对区块执行共识算法(工作量证明PoW、权益证明PoS等);
  4. 区块通过共识算法过程后被正式纳入区块链中存储,全网节点均表示接受该区块。而表示接受的方法,就是将该区块的随机散列值视为最新的区块散列值,新区块的制造将以该区块链为基础进行延长。

1.png

0×02 区块链结构

2.1 区块

区块是记录在一段时间内发生的交易和状态,是对当前账本状态的一次共识,它由一个包含元数据的区块头和紧跟其后的构成区块主体的一长串交易组成。区块头是80字节,而平均每个交易至少是250字节,平均每个区块至少包含超过500个交易。

Image

下一区块头hash最大值=后三字节(难度目标)*2^(8*(第一字节(难度目标)-3))
挖矿难度=创世区块链下一区块头hash最大值/下一区块头hash最大值
比特币地址=*1*+Base58(0+公钥hash160+前四字节(hash256(0+公钥hash160))) 
hash160(x)=Ripemd160(sha256(x))  
Ripemd160原始完整性校验消息摘要,建立在md的基础之上,所以,其添加数据的方式和md5完全一样。

每个区块都有一个区块标识符,区块标识符包含区块头哈希值(区块主标识符)和区块高度,区块头哈希值可以唯一、明确的标识一个区块,并且任何节点通过简单地对区块头进行哈希计算都可以独立地获取该区块头哈希值。区块头哈希值实际上并不包含在区块的数据结构里,不管是该区块在网络上传输时,抑或是它作为区块链的一部分被存储在某节点的永久性存储设备上时。区块头哈希值是当该区块从网络被接收时由每个节点计算出来的。区块的哈希值可能会作为区块元数据的一部分被存储在一个独立的数据库表中,以便于索引和更快地从磁盘检索区块。区块高度是可以通过该区块在区块链中的位置识别区块的另一种方式。第一个区块,其高度为0,每一个随后被存储在第一个区块之上的区块在区块链中都比前一区块“高”出一个位置,就像箱子一个接一个堆叠在其他箱子之上。和区块头哈希值不同的是,区块高度并不是唯一的标识符,在区块链的增长过程中可能会出现两个或两个以上的区块有同样的高度,这种情况叫做“区块链分叉”

2.2 区块链

当一个节点从网络接受到传入的区块时,它会验证这些区块,然后链接到现有的区块链上,形成如下区块链:13.png

0×03 区块链安全

区块链技术之所以能够大受欢迎,其安全的特性起到一定的推动作用,大家都认为区块链安全到几乎无可摧残。虽然区块链利用类似工作量证明等共识机制来解决拜占庭将军问题和防止恶意攻击,同时还使用公私钥加解密、ECDSA签名、数字证书等方式生成每个用户的地址(例:比特币钱包)确保交易安全。但是其交易数据默认是完全透明不加密的。下面先看看生成比特币公私钥、地址、签名等具体代码实现。比特币使用的HASH160和HASH256散列算法

#define HASH256_SIZE (32)
#define HASH160_SIZE (20)
size_t Hash256(const unsigned char * begin, size_t size, unsigned char to[])
{
unsigned char hash[HASH256_SIZE];
if(NULL == begin || size == 0) return 0;
SHA256(begin, size, (unsigned char *)&hash[0]);
SHA256(&hash[0], sizeof hash, (unsigned char *)&to[0]);
return HASH256_SIZE;
}
size_t Hash160(const unsigned char * begin, size_t size, unsigned char to[])
{
unsigned char hash[HASH256_SIZE];
if(NULL == begin || size == 0) return 0;
SHA256(begin, size, (unsigned char *)&hash[0]);
RIPEMD160(&hash[0], sizeof hash, &to[0]);
return HASH160_SIZE;
}

比特币私钥为一串256位的随机数取值范围在[1,n-1]之间其中n (order) = FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFE BAAEDCE6 AF48A03B BFD25E8C D0364141

BOOL ECKey_Check(const unsigned char vch[32]);
uint32_t ECKey_GeneratePrivKey(EC_KEY * pkey, unsigned char vch[32])
{
RandAndSeed(); // 初始化随机数种子
do
{
RAND_bytes(vch, 32); // 利用openssl库生成一个256位的随机数
}while(!ECKey_Check(vch)); // 检查取值范围是否合法
if(pkey != NULL) return ECKey_GenKeypair(pkey, vch); // 生成密钥对
return 32; // 私钥的字节数
}
BOOL ECKey_Check(const unsigned char vch[32])
{
static const unsigned char order[32] = {
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFE,
0xBA,0xAE,0xDC,0xE6,0xAF,0x48,0xA0,0x3B,
0xBF,0xD2,0x5E,0x8C,0xD0,0x36,0x41,0x40
};
BIGNUM bn; // 私钥
BIGNUM bnOrder; // G在Fp下的序号order
BIGNUM bn0; // 0
BN_init(&bn);
BN_init(&bnOrder);
BN_init(&bn0);
BN_zero(&bn0);
BN_bin2bn(vch, 32, &bn); //将二进制序列转化为一个大整数
BN_bin2bn(order, 32, &bnOrder);
//** 0 < [私钥] < order
if(BN_is_zero(&bn)) return 0; // 私钥不能为0
if(BN_cmp(&bn, &bnOrder) > 0) return 0; //私钥必须小于order
return 1;
}

生成公钥

//** 初始化EC_KEY,告知openssl库将使用secp256k1椭圆曲线。
EC_KEY * ECKey_new()
{
return EC_KEY_new_by_curve_name(NID_secp256k1);
}
uint32_t ECKey_GenKeypair(EC_KEY * pkey, unsigned char vch[HASH256_SIZE])
{
//** pkey = ECKey_new();
const uint32_t key_size = HASH256_SIZE;
const EC_GROUP * group;
BIGNUM bn;
BIGNUM * privkey = &bn;
BN_CTX * ctx = NULL;
EC_POINT * pubkey = NULL;
if(NULL == pkey) return 0;
BN_init(&bn); // BIGNUM使用前最好先初始化,否则windows + mingw环境下有时会出错
group = EC_KEY_get0_group(pkey); // group结构体中存储了G值和运算规则
pubkey = EC_POINT_new(group); // 给pubkey分配内存,pubkey为曲线上的一个点
ctx = BN_CTX_new();
if(NULL == pubkey || NULL == ctx) goto label_errexit;
if(BN_bin2bn(vch, key_size, &bn)) // 将私钥(二进制形式)转化为一个大整数
{
if(EC_POINT_mul(group, pubkey, privkey, NULL, NULL, ctx)) // pubkey =privkey*G
{
// 将密钥存储于EC_KEY结构体中,便于导出为所需的格式
EC_KEY_set_private_key(pkey, privkey);
EC_KEY_set_public_key(pkey, pubkey);
}
BN_clear_free(&bn);
}
EC_POINT_free(pubkey);
BN_CTX_free(ctx);
return key_size;
label_errexit:
if(NULL!=pubkey) EC_POINT_free(pubkey);
if(NULL != ctx) BN_CTX_free(ctx);
return 0;
}

Base58check编码生成比特币地址

uint32_t PubkeyToAddr(const unsigned char * pubkey, size_t size, char *to)
{
struct
{
unsigned char version;
unsigned char vch[20];
unsigned char checksum[4];
}ext_pubkey;
unsigned char hash[32]={0};
printf("ext_pubkey size: %d\n", sizeof(ext_pubkey));
ext_pubkey.version = 0x00;
Hash160(pubkey, size, &ext_pubkey.vch[0]);
Hash256(&ext_pubkey.version, 1+20, hash);
memcpy(ext_pubkey.checksum, hash, 4);
return Base58Encode((unsigned char *)&ext_pubkey.version, sizeof(ext_pubkey), to);
}

签名

size_t ECKey_Sign(EC_KEY *pkey, const unsigned char hash[HASH256_SIZE], unsigned char **to)
{
//** if (*to) == NULL, the caller should use OPENSSL_free(*to) to free the memory
size_t cb = 0;
ECDSA_SIG *sig = NULL;
BN_CTX * ctx = NULL;
BIGNUM order; // The order of G
BIGNUM halforder; // get sign/unsign mark
unsigned char *output = NULL;
const EC_GROUP * group = EC_KEY_get0_group(pkey); // secp256k1: G
if(NULL == group) return 0;
sig = ECDSA_do_sign((unsigned char *)&hash[0], HASH256_SIZE, pkey);
if(NULL == sig) return 0;
//** sig = (r,s) = (r,-s)
//** s must less than order/2, otherwise, some app may parse '-s' as a large unsigned positive integer
ctx = BN_CTX_new();
if(NULL == ctx) goto label_exit;
//** allocate memory for bignum
BN_init(&order);
BN_init(&halforder);
// get the order of G
EC_GROUP_get_order(group, &order, ctx); // secp256k1: n
BN_rshift1(&halforder, &order);
if(BN_cmp(sig->s, &halforder)>0)
{
// if s > order/2, then output -s. (-s = (order - s))
BN_sub(sig->s, &order, sig->s);
}
BN_CTX_free(ctx);
output = *to;
cb = ECDSA_size(pkey);
if(NULL == output)
{
output = (unsigned char *)OPENSSL_malloc(cb);
if(NULL == output) goto label_exit;
}
if(NULL == *to) *to = output;
//** i2d_ECDSA_SIG DER encode content of ECDSA_SIG object
//** (note: this function modifies *pp (*pp += length of the DER encoded signature)).
//** do not pass the address of 'to' directly
cb = i2d_ECDSA_SIG(sig, &output);
label_exit:
ECDSA_SIG_free(sig);
return cb;
}

可以看到上面区块链使用了目前非常主流的加密、签名等方案来确保其安全性,但是再安全的系统也会存在安全问题,下面分几个方面分析区块链可能存在的安全问题。

3.1 密钥安全

密码技术是区块链的核心技术之一,保证了区块链不可逆,不可伪造。因此密码技术中秘钥的存储、传输等安全风险在区块链中同样存在。区块链没有第三方,私钥由每个用户各自保管(比特币使用的是冷存储离线保存),用户如若存储的设备感染病毒则可能会导致私钥丢失,一旦私钥丢失用户则相当于失去了对自身数据或者资产的控制权。区块链由于去中心化,也就没有私钥补发与管理机制,因此私钥一旦丢失即无法找回。

3.2 隐私保护

区块链的隐私保护也存在安全性风险。一个区块的数据中,包含了所有交易的记录以及账户身份信息,交易信息在区块链中是公开的,账户身份信息是通过非对称加密算法加密的。所有人都可以获取到,因此如果交易信息存在一定的敏感性,那么就存在一定的风险。另外区块链系统内各节点并非完全匿名,而是通过类似电子邮件地址的地址标识 (例如比特币公钥地址) 来实现数据传输。虽然地址标识并未直接与真实世界的人物身份相关联,但区块链数据是完全公开透明的,随着各类反匿名身份甄别技术和大数据技术的发展,通过数据整合分析可能实现部分重点目标的定位和识别。

3.3 拒绝服务

很多人一看到区块链去中心化的特点会觉得区块链在应对拒绝服务方面相比现有的中心化系统有一定的优势,会更加灵活,点对点,多冗余,其中一个节点遭受拒绝服务攻击也不会影响整个系统。然而如果没有适当的机制来协调控制,当一个节点遭受攻击时,虽然不会影响整个系统,但是与该节点连接的用户则无法进行相应的操作。另外,区块链客户端如果存在安全漏洞,同样会存在类似目前移动APP一样的拒绝服务问题,类似的事件有以太坊钱包Geth客户端崩溃导致以太币(ETH)交易市场发生临时性恐慌抛售事件分叉以太坊(ETH)DDoS攻击

3.4 针对技术实现攻击

每一个系统设计实现会有缺陷,就算设计是安全的,代码实现也会存在一定的风险。DAO被攻击事件主要是代码实现存在问题从技术角度剖析针对THE DAO的攻击手法,一是DAO余额扣减和Ether转账这两步操作的顺序有误,二是不受限制地执行未知代码给攻击提供了可能性。另外,Bitfinex多重签名攻击由于两个平台之间相互信任,其中一个平台被黑客攻击后,利用被攻击平台发出的请求另外一个平台都认为是合法的,因此破坏了多重签名的安全性。

Bitfinex多重签名攻击根据公开的信息显示,bitfinex平台保存用户资产的方式和其它平台有所不同。其它平台一般都把大部分币作冷储存(离线不联网)处理,只留下少部分币在热钱包(在线)用于用户提现使用。而bitfinex同样也为了安全,和Bitgo(一家比特币安全平台)联合,对每个用户的币进行多重签名处理。多重签名的意思是Bitfinex用户要提现比特币的时候,Bitfinex平台先确认一次,然后再通知Bitgo确认,两家公司都确认无误后才给用户的提现操作放行。因为Bitfinex平台期望做到资金透明化,把每个用户的币都独立存放(100%备付、资金流水清晰),每个用户都使用不同的多重签名地址,每个用户的提现操作都需要经过Bitfinex和Bitgo两家公司确认。每个用户的币单独储存,所以我们看到公告称“部份用户的币被盗”。错就错在,Bitfinex和Bitgo多重签名的安全方案,必须自动化处理,必须把所有用户的多重签名地址联网处理。Bitgo必须要假设Bitfinex服务器是安全的才可以开展工作,Bitgo没有义务去保证Bitfinex服务器请求的正当性。只要是Bitfinex服务器发起的提现请求,Bitgo可能都会全部通过。这样,当Bitfinex服务器被黑客攻破,直接在Bitfinex服务器发起提现请求时,Bitgo就会把币发出去。

虚拟货币被黑客攻击的事件越来越多,虽然攻击可能是系统其他地方存在风险导致,但是区块链的特性也导致了系统在实现上跟安全性有一定的冲突。

0×04 总结

区块链技术目前已经在一些场景(公益慈善、支付网络、金融交易等)应用到实际生活中。然而其不只是存在像比特币一样常见的51%攻击、性能等问题,针对其加密技术、密钥存储、隐私保护、技术实现等方面的安全风险会成为发展中重大挑战之一。

0×05 参考

https://www.gitbook.com/book/yeasy/blockchain_guide/details

https://github.com/imfly/bitcoin-on-nodejs/blob/

http://toutiao.com/i6297561196912443906/

http://www.360doc.com/content/16/0503/20/29322182_555996668.shtml

* 本文原创作者:白泽安全团队

未经允许不得转载:安全路透社 » 浅析互联网后最具颠覆性创新技术——区块链安全

赞 (0)
分享到:更多 ()

评论 0

评论前必须登录!

登陆 注册