天才程序员: "那些年我偷懒没敲的EOS代码, 让我失去了一切, 如果..."
作者 | 红石
责编 | 乔治
出品 | 区块链大本营(blockchain_camp)
#今天是一篇技术文。
3月15日,mercatox 遭受(hard_fail)攻击,黑客获利数千 EOS,约合数万人民币。
3月11日,EOS DApp nkpaymentcap 被攻击,黑客成功获利 5 万 EOS,约合人民币100多万元。经分析发现,攻击者采用假转账通知攻击获取大量合约代币,又将代币通过 DApp 合约兑换成真 EOS 进行套现。
3月10日,EOS 竞猜类游戏 Vegas Town 被连续(hard_fail)攻击,黑客获利数千枚 EOS 。
3月9日,EOS 竞猜类游戏 Gamble EOS 遭受假转账攻击,黑客成功获利数千 EOS……
仅仅三月份,利用交易验证漏洞进行的攻击就已经有这么多起,损失达上千万人民币。
那么,什么是交易验证漏洞?为何 EOS 让你频频“丢钱”?BM告诉你,是你的代码“太笨”。
先说说交易验证,你不了解交易验证,但黑客了解。
因为在支付领域,这很重要。在区块链领域,无论做 DApp,还是接入数字货币支付,交易验证都是重要部分。
交易验证,说起来也简单:就是如何确认一笔金额已经到账。
说起来也不简单,因为会有无数黑客试图让并未成功的交易通过验证,从而空手套白狼。
比如最近针对 EOS 交易的 hard_fail 状态攻击,就是这样一种黑客攻击。
hard_fail 状态攻击
在 EOS 区块链上,每笔交易(transaction)都有一个状态(status)参数,只有当这个参数为 executed(已执行),才说明交易成功。但是因为一般来说,失败的交易都不会提交到链上,所以,一些不谨慎的交易所、DApp 甚至没有验证这个参数。
这才有了最近的 hard_fail 状态攻击。其实这个攻击手法的背后原理远比它的名字简单,就是黑客发起了注定失败的、但是又能上链的交易,专门攻击那些只要交易上链就视作交易成功的平台。
不试不知道,一试吓一跳,真的有很多平台没验证这个参数……
那么,EOS 交易验证到底需要验证些啥?
EOS 交易验证涉及的参数
EOS 交易验证,需验证:
1、交易 excuted,验证 transaction status 参数为 executed,验证这个参数可以有效避免 hard_fail 状态攻击;
说简单点,这一步是验证交易是否正常执行。
2、不可逆,即交易所在区块号低于当前最新不可逆块号,需要获得 transaction 所在区块的区块号,以及主网最新不可逆块的区块号(不可逆区块高度),判断:
block_num < last_irreversible_block_num;
说简单点,这一步是验证交易是否已经同步。
区块链是分布式账本,交易提交上去后,需要大多数节点记录了这笔交易,才能认为交易已上链并不可篡改。不然的话,比如如果只有一个节点有这笔交易,则只要这个节点的交易信息一改,这笔交易就变了。
3、合约账户和货币符号;
合约账户就是货币的智能合约账户。EOS 区块链转账都是基于智能合约的,比如 EOS 币的智能合约账户就是 eosio.token,每一次进行 EOS 币转账,都会调用这个合约。
假币攻击就是因为交易所没验证合约账户。
4、交易(action)类型为 transfer;
EOS 区块链上的交互都是以 transaction 进行,无一例外。所以,不是每一笔 transaction 都包含转账。EOS 一笔 transaction 可以有多个 action,只有类型为 transfer(转账)的 action,才是转账,才是需要做交易验证的。
5、From 和 to,即转入转出的账户需要再次确认。
交易(Transaction)同时满足这些条件,才能判断为交易成功,并执行下一步程序。而且,如果是通过公共 API 或 API 服务商提供的数据进行交易验证,需要使用不同服务提供商的 API 至少进行二次确认,以防止 API 信息出错导致问题。
那么问题又来了,如何通过公共 API 进行交易验证呢?
通过 EOSPark API 获取交易、进行交易验证
让我们以 EOSPark 的 API 服务做个基本示例。
EOSPark 本身是一个主流 EOS 区块浏览器,但他们也面向开发者提供 API、代码一致性校验、合约安全(SEC)、合约语义化等服务。
1、EOSPark API 官网:
https://eospark.com/openapi
2、EOSPark API 官方文档:
https://developer.eospark.com/api-doc/zh/https/
EOSPark API 服务思维导图:
EOSPark API 有四种查询 EOS 交易的方式。
根据账户查询:
HTTPS API get_account_related_trx_info
Websocket API subscribe_account
根据 txID 查询:
HTTPS API get_transaction_detail_info
HTTPS API get_transaction_action_info
以 HTTPS API get_account_related_trx_info 为例,这个接口能查询对应账户的进出交易,无论是收到的转账还是发起的转账,都可以一起查到:
get_account_related_trx_info 的基本查询语句如下:
https://api.eospark.com/api?module=account&action=get_account_related_trx_info&apikey=
{这里放你的 API KEY}&account={这里放 EOS 账户名}&page=1&size=10
语句填好参数后可以直接在普通浏览器中打开查询信息,不过当然,我们更习惯用 IDE:
Node.js 代码示例:
返回 JSON 示例:
可以看到在 get_account_related_trx_info 返回的信息中,本来就包括交易所在区块号(block_num)和不可逆区块高度(last_irreversible_block_num)。
同时 status、code(合约账户)、symbol、From(这里是 sender)和 to(这里是 receiver)这些参数也一应俱全。(交易类型因为这个接口本身就是返回转账交易,所以这里可以不作验证。)
也就是说,使用这个接口,查询一次就可以直接验证获取到的交易。
那么问题又来了,也就是说,有些时候查询的信息不能直接进行交易验证?
很不幸,是滴。
获取不可逆区块高度和交易状态的补充方法
有些接口返回的交易信息不包含交易验证所需所有参数,需要再另外获取。最常见的就是不可逆区块高度的缺失,还有一些直接查询 actions 的接口有交易状态参数缺失。
不过处理起来都很简单。
同样以 EOSPark API 服务为例:
获取不可逆区块高度,使用 RPC 接口 get_info 就好,这是一个获取 EOS 主网基本信息的接口:
Node.js 代码示例:
返回 JSON 示例:
获取状态参数,可以使用 HTTPS 接口 get_transaction_detail_info,这是一个根据 txID 查询交易(transaction)详情的接口:
查询语句:
https://api.eospark.com/api?module=transaction&action=get_transaction_detail_info&apikey=
{这里放你的API KEY}&trx_id={这里放查询的交易ID}
返回 JSON 示例:
至此,我们就简单说完了 EOS 区块链交易验证的一个基本思路。当然,具体情况具体分析,具体开发时验证的方式不一定按这样来。不过条条大路通罗马,思路是一样的,验证的参数也基本都是这些。
命令千万条,安全第一条。
代码不齐全,亲人两行泪。
欢迎补充,欢迎拍砖!
红石,氢石网络科技CEO,
DApp 独立开发者,区块链技术顾问,资深营销人,摄影设计师。
技术架构 | 应用架构 | 安全 | 隐私
推荐阅读:
猛戳"阅读原文"有惊喜哟!
老铁在看了吗?👇