4.3.3 防重放攻击
重放攻击即为:攻击者“重放”一则在网络上“窃听”到,或者在区块链中“偷窥”到的消息。重放攻击是一个很大的问题,因为它们可以引发验证节点重做一次计算密集型处理(即调用智能合约),同时可能影响到相应合约的状态。而这些过程,并不需要或只需要耗费攻击者很少的资源。如果一个事务是处理支付的,那么问题就会更加严重,消息重放可能会引发支付又被处理一遍,并且不需要原始支付者的参与。现有的系统防重放攻击有如下方式:
* 在系统中记录事务哈希值。这个方案需要验证者维护一份哈希日志,记录每一个已被网络广播的事务哈希值,然后每收到一个新的事务,就和本地存储值进行对比。很明显,这种方式无法扩展到大规模网络环境中,并且很容易就会导致验证者花费大量的时间检查该事务是否属于重放,而不是执行实际事务处理。
* 利用每个用户身份标识维护的状态(Ethereum的做法)。以太坊保存一些状态,例如,为系统中每一个标识/昵称 维护一个计数器(初始化为1)。用户也为自己的每一个身份/昵称 维护一个计数器(初始化为0)。每一次用户使用一个身份/昵称 发送事务时,他都会将本地计数器加1,并将结果添加到事务中。随后使用用户标识将事务进行签名,并发布到网络中。当收到这个事务时,验证者就会核对包含在事务中的计数器值,并与他们本地存储的值对比;如果相等,他们就将本地计数器值加1,同时接受该事务。否则,他们认为该事物非法或者属于重放,并拒绝它。尽管在有限数量(比如,数量不太大)的用户标识/昵称前提下,这个方案表现不错,但是当用户每一个事务,都使用不同的身份标识(事务证书TCA)时,就会导致用户昵称数量正比于事务数量,那么此时,这种方案就从根本上,无法进行大规模扩展。
其它的资产管理系统,比如,比特币,虽然并没有直接处理重放攻击,但是它们却可以防止重放。在管理(数字)资产的系统中,状态维护在每一个资产基础中,例如,验证者只用保存一条记录,指示谁拥有什么。由于根据协议,事务重放会被立即判断为非法,这样就直接防止了重放攻击,。(因为来自于资产的上一个拥有者的事务,只能用来显示)。这么做对于资产管理系统是恰当的,但是作为一个比资产管理更加通用的区块链系统,这样做并不符合实际需要。
在fabric中,使用一种混合方法来防止重放攻击。即,用户在事务中添加一个nonce,根据事务是匿名事务(遵守TCA,并且由TCA签名),还是非匿名事务(遵守长期有效的ECA,并且由其签名),系统会使用不同的方式来生成nonce。具体来说:
* 当用户使用他们的EC提交事务时,需要在该事务中包含一个nonce,它是上一次使用同样证书,提交事务时使用的nonce的函数。(例如,可以是一个计数函数,或者是一个hash函数)。在第一次使用EC提交的事务中,nonce可以由系统预定(例如,包含在创世区块中),也可以由用户选定。前者,创世区块需要包含nonceall,例如,一个固定数字,它和用户使用EC签名的第一次事务中的身份IDA,相互作用产生nonce:
$$ nonce_{round_{0}IDA} <- hash(IDA, nonce_{all}) $$
IDA存在EC中。从该点开始,后续使用EC提交的事务,都需要包含一个nonce,该nonce产生规则为:
$$ nonce_{round_{i}IDA} <- hash(nonce_{round_{\{i-1\}}IDA}) $$
即第i个事务使用的nonce,是第{i-1}个EC事务nonce的哈希值。只要满足上述条件,验证者就继续处理该事务,并且更新数据库中的nonce值。
存储开销:
* 用户端:只需要存储最近使用的nonce值
* 验证者端:O(n),n是用户数量
* 用户使用TC提交事务时,需要在事务中包含一个随机nonce,需要保证2个事务不能映射到同一哈希值。如果该事务的TC没有过期,验证者就将该事物的hash值存储到本地数据库,利用TC的有效期,来避免存储大量的hash值。特别的,在当前或未来有效期内,验证者会维护一个已接受事务哈希值的更新记录。
存储开销(这里只涉及到验证者):`O(m)`,m近似于一个对应标识符的有效期内的事务数量。
**Registrar API(member services)**
* POST /registrar
* GET /registrar/{enrollmentID}
* DELETE /registrar/{enrollmentID}
* GET /registrar/{enrollmentID}/ecert
* GET /registrar/{enrollmentID}/tcert
使用Registrar APIs管理终端用户注册CA服务。这些