对黑客说不!使用 EOSPark API 进行 EOS 区块链交易验证的思路分析

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 区块链生态中利用交易验证漏洞进行的攻击,造成的损失就达上千万人民币。

人们不了解交易验证。

但是黑客了解。

因为在支付领域,这很重要。在区块链领域,无论做 DApp,还是接入数字货币支付,交易验证都是重要部分。

交易验证,说起来也简单:就是如何确认一笔金额已经到账。

说起来也不简单,因为会有无数黑客试图让并未成功的交易通过验证,从而空手套白狼。

比如最近针对 EOS 交易的 hard_fail 状态攻击,就是这样一种黑客攻击。

对黑客说不!使用 EOSPark API 进行 EOS 区块链交易验证的思路分析_第1张图片

hard_fail 状态攻击

在 EOS 区块链上,每笔交易(transaction)都有一个状态(status)参数,只有当这个参数为 executed(已执行),才说明交易成功。但是因为一般来说,失败的交易都不会提交到链上,所以,一些不谨慎的交易所、DApp 甚至没有验证这个参数。

这才有了最近的 hard_fail 状态攻击。其实这个攻击手法的背后原理远比它的名字简单,就是黑客发起了注定失败的、但是又能上链的交易,专门攻击那些只要交易上链就视作交易成功的平台。

不试不知道,一试吓一跳,真的有很多平台没验证这个参数……

Well,那么,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.Fromto,即转入转出的账户需要再次确认。

交易(Transaction)同时满足这些条件,才能判断为交易成功,并执行下一步程序。而且,如果是通过公共 API 或 API 服务商提供的数据进行交易验证,需要使用不同服务提供商的 API 至少进行二次确认,以防止 API 信息出错导致问题。

那么问题又来了,如何通过公共 API 进行交易验证呢?

通过 EOSPark 的 API 获取交易进行交易验证

让我们以 EOSPark 的 API 服务做个基本示例。

EOSPark 本身是一个主流 EOS 区块浏览器,但他们也面向开发者提供 API、代码一致性校验、合约安全(SEC)、合约语义化等服务。

EOSPark API 官网:https://eospark.com/openapi

EOSPark API 官方文档:https://developer.eospark.com/api-doc/zh/https/

EOSPark API 服务思维导图:

对黑客说不!使用 EOSPark API 进行 EOS 区块链交易验证的思路分析_第2张图片
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

对黑客说不!使用 EOSPark API 进行 EOS 区块链交易验证的思路分析_第3张图片
EOSPark API 查询交易

这里以 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 代码示例:

const fetch = require('node-fetch');

fetch('https://api.eospark.com/api?module=account&' +
    'action=get_account_related_trx_info&' +
    'apikey={这里放你的 API KEY}&' +
    'account={这里放 EOS 账户名}&page=1&size=10', {
    method: 'get',
}).then(response => response.json()
    .then(data => console.log(data.data)));

返回 JSON 示例:

{
  "errno": 0,
  "errmsg": "",
  "data": {
    "trace_count": 205041,
    "last_irreversible_block_num": 48019699,
    "trace_list": [
      {
        "data_md5": "f75f4f16392dc7b27dc31c4e9713f4c2",
        "trx_id": "4b173d9a6484a2e9eded03fa490efa2a374dde10308a6351a109fa9af9d19c83",
        "timestamp": "2019-03-17T03:33:49.000",
        "receiver": "eosio.vpay",
        "sender": "eosio",
        "code": "eosio.token",
        "quantity": "344.5620",
        "memo": "fund per-vote bucket",
        "symbol": "EOS",
        "status": "executed",
        "block_num": 48020026
      },
      {
        "data_md5": "ecf5c5ae13ce70f1a158509d1173c9b6",
        "trx_id": "4b173d9a6484a2e9eded03fa490efa2a374dde10308a6351a109fa9af9d19c83",
        "timestamp": "2019-03-17T03:33:49.000",
        "receiver": "eosio.bpay",
        "sender": "eosio",
        "code": "eosio.token",
        "quantity": "114.8539",
        "memo": "fund per-block bucket",
        "symbol": "EOS",
        "status": "executed",
        "block_num": 48020026
      }
    ]
  }
}

可以看到在 get_account_related_trx_info 返回的信息中,本来就包括交易所在区块号(block_num)和不可逆区块高度(last_irreversible_block_num)。同时statuscode(合约账户)、symbolFrom(这里是 sender)和 to(这里是 receiver)这些参数也一应俱全。(交易类型因为这个接口本身就是返回转账交易,所以这里可以不作验证。)

也就是说,使用这个接口,查询一次就可以直接验证获取到的交易。

那么问题又来了,也就是说,有些时候查询的信息不能直接进行交易验证?

很不幸,是滴。

获取不可逆区块高度和交易状态的补充方法

有些接口返回的交易信息不包含交易验证所需所有参数,需要再另外获取。最常见的就是不可逆区块高度的缺失,还有一些直接查询 actions 的接口有交易状态参数缺失。

不过处理起来都很简单。

同样以 EOSPark API 服务为例:

获取不可逆区块高度,使用 RPC 接口 get_info 就好,这是一个获取 EOS 主网基本信息的接口:

Node.js 代码示例:

const fetch = require('node-fetch');

fetch("https://api.eospark.com/v1/chain/get_info?apikey=/*这里放你的API KEY*/")
    .then(response => response.json()
        .then(data => console.log(data)));

返回 JSON 示例:

{
    "server_version": "0f6695cb",
    "chain_id": "687fa513e18843ad3e820744f4ffcf93b1354036d80737db8dc444fe4b15ad17",
    "head_block_num": 20583056,
    "last_irreversible_block_num": 20583039,
    "last_irreversible_block_id": "013a127fab9a79403a20b55914cdc7e1ac136618387325ad3c1914d27528a1f1",
    "head_block_id": "013a129048f4486ce8a5ac8380870a8ce1bcbd4ff45b40fd0792503dc44c427d",
    "head_block_time": "2019-01-25T16:39:38.000",
    "head_block_producer": "blkproducer1",
    "virtual_block_cpu_limit": 200000000,
    "virtual_block_net_limit": 1048576000,
    "block_cpu_limit": 199900,
    "block_net_limit": 1048576,
    "server_version_string": "v1.3.0"
}

获取状态参数,可以使用 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 示例:

{
  "errno": 0,
  "errmsg": "Success",
  "data": {
    "block_num": 48400644,
    "cpu_usage_us": 934,
    "eospark_trx_type": "ordinary",
    "net_usage_words": 13,
    "status": "executed",
    "timestamp": "2019-03-19T08:29:01.500",
    "trx": {
      "compression": "none",
      "context_free_data": [],
      "id": "b887096b4dddfc103311789dbbff9c0435dcdf8811fab6599f32acf6b833e5d8",
      "packed_context_free_data": "",
      "packed_trx": "6ba8905cbc87d0fb0c5000000000010000000000ea305580d3355c5de94c440150cfa54b4d8aa96200000000a8ed32320850cfa54b4d8aa96200",
      "signatures": [
        "SIG_K1_KZfPeMSKyhp1BAM93b2EkGQaJCeLPfgb56qggfLKupsqBLy1bn9ZexZ6gy4C4sghKXBthTtSLVwbzrRRQzHSwfSy4yVtXk"
      ],
      "transaction": {
        "actions": [
          {
            "account": "eosio",
            "authorization": [
              {
                "actor": "geosoneforbp",
                "permission": "active"
              }
            ],
            "data": {
              "owner": "geosoneforbp"
            },
            "hex_data": "50cfa54b4d8aa962",
            "name": "claimrewards"
          }
        ],
        "context_free_actions": [],
        "delay_sec": 0,
        "expiration": "2019-03-19T08:29:31",
        "max_cpu_usage_ms": 0,
        "max_net_usage_words": 0,
        "ref_block_num": 34748,
        "ref_block_prefix": 1343028176,
        "transaction_extensions": []
      }
    }
  }
}

至此,我们就简单说完了 EOS 区块链交易验证的一个基本思路。当然,具体情况具体分析,具体开发时验证的方式不一定按这样来。不过条条大路通罗马,思路是一样的,验证的参数也基本都是这些。

欢迎补充,欢迎拍砖!


原创内容,欢迎转载,但转载请标明出处。

我们有一个区块链知识星球,做区块链前沿资料的归纳整理以方便大家检索查询使用,也是国内顶尖区块链技术社区,欢迎感兴趣的朋友加入。如果你对上面内容有疑问,也可以加入知识星球提问我:

对黑客说不!使用 EOSPark API 进行 EOS 区块链交易验证的思路分析_第4张图片
区块链社群 知识星球

你可能感兴趣的:(对黑客说不!使用 EOSPark API 进行 EOS 区块链交易验证的思路分析)