重放攻击
https://blockchain.iethpay.com/replay-attack-resistent.html
-
在系统中记录交易的哈希值。这个解决方案需要验证节点维护一个已经执行过的每笔交易哈希值的日志,然后接收到或执行一笔新交易的时候,将其与他们本地存储的交易记录进行比对。很明显,这种解决办法不能适应大型网络的需要,很容易就导致验证者花费大量时间去检查一笔交易是否被重放,比执行交易的时间都要长。
-
利用每个用户实体维护的状态 (Ethereum)。Ethereum 中,每一个账户都有一个
nonce
,该值等于从该账户中发出的交易。如果该账户是一个合约账户,该值等于由该合约账户创建的新合约账户的数量。当一笔交易被矿工验证是否有效的时候,矿工会比对交易中的nonce
与该交易的发送者账户中的nonce
是否相等,交易其它验证通过和执行完成后,发送者账户中的nonce
会自增 1,因此当有重复交易过来的时候,会直接被判为无效,从而阻止了重放攻击。这种方法对于存在有限实体账户的系统来说工作地很好,但是对于用户的每笔交易使用不同标识的系统来说 (fabric 中的 Tcert 交易证书),这种方法从根本上扩展性也不高,因为将有与交易数量成比例的大量用户笔名 (一个用户对应着很多 Tcert 即笔名)。 -
其它的资产管理管理系统,例如,比特币,尽管没有直接地去处理重放攻击,它们却能抵抗重放攻击。在这些管理数字资产的系统中,采取了
UTXO
模型,交易的串联构成了系统中用户的状态。这样的系统对重放攻击是天生免疫的,因为每一笔交易的输入指定它前面出现过的交易的未花费输出 (UTXO),并产生新的 UTXO。交易重放攻击会直接失败,因为再次执行的交易的输入指向的 UTXO 已经不存在了。但是这种方法却不适用于更加通用的区块链系统。 -
Hyperledger fabric 中,采用了一种混合式解决办法。那就是,用户在交易中加入
nonce
值,该nonce
值的生成方法根据该交易是否保持匿名有关,交易匿名指交易被 Tcert 签名,非匿名指交易被 Ecert 签名。更具体的:-
用户使用他们的 Ecert 提交一笔交易的时候,在交易中包含的
nonce
值,是他们用相同 Ecert 提交的上一笔交易中使用的nonce
值经过函数 (哈希函数或者计数器函数) 的变换得到的。相同 Ecert 提交的第一笔交易中的nonce
值要么是系统中提前设置好的 (例,包含在创世区块中) 要么是被用户自己选择的。在第一种情况中,创世区块需要包含nonceall
,例如,假定用户的实体标识 IDA,则他使用Ecert
签名的第一笔交易中的nonce
值为nonce(round[0]IDA) <- hash(IDA, nonceall)
,其中的 IDA 可认为是 Ecert。从该时刻开始,后继使用相同 Ecert签名的交易,其中的nonce
值为nonce(round[i]IDA) <- hash(nonce(round[i-1]IDA))
,意思就是第i
笔交易中的nonce
将会使用 第i - 1
笔交易中nonce
的哈希值 (都是指的同一个 Ecert 下的交易)。验证者根据此规则验证交易中的nonce
值,即将其与本地存储的 Ecert 对应的nonce
值比对,以及其它约定好的协议规则验证交易,交易通过验证后,验证者将交易存入本地存储中,并更新相应 Ecert 对应的nonce
值。 存储开销: a). 用户这方:仅仅需要存储最近使用的nonce
值;b). 验证节点这方:O(n),n 是用户的数量。 -
用户使用他们的 Tcert 提交一笔交易的时候,在交易中应该包含一个随机的
nonce
值,这将会保证两笔交易不会形成相同的哈希值。验证节点将哈希值存储在本地数据库中,如果该笔交易使用的 Tcert 没有过期的话。所以,验证节点在 Tcert 当前或未来的有效期内保持该 Tcert 签名的交易哈希的更新记录。存储开销: 仅仅对于验证节点有意义:O(m),m 是 Tcerts 有效期内大约交易的数量。
-