本篇技术文章源自于 Nervos 每周三举办的 Dev Meetup,作者为秘猿科技 Nervos AppChain 技术总监段扬扬。
---
可能很多人都玩过区块链 DApp,如加密猫(CryptoKitties),当你看到一只特别可爱的猫,想要购买时,通常你会看到需要下载安装 MetaMask 的提示。MetaMask 是一款基于 PC 浏览器的插件钱包,要想下载安装成功,你还需要懂一点科学上网的知识,安装成功后,就可以通过唤起 MetaMask 插件钱包完成支付交易。
但是,如果你想在手机上玩加密猫,就会发现因为没有 MetaMask 钱包而无法继续游戏。或许你的手机里还有 imToken 等手机钱包,令人遗憾的是如果你通过手机浏览器打开加密猫游戏,依然是无法自动唤醒 imToken 等钱包进行签名支付。
多平台签名问题和痛点
所以你会发现,DApp 有很多承载方式,有基于 PC 浏览器的应用,也有手机原生 APP 应用。同样的,钱包也有很多承载方式,有诸如 imToken 手机客户端钱包,也有诸如以太坊官方钱包那样基于 PC 客户端钱包,也有诸如 MyEtherWallet 的开源 web 版钱包,还有各种各样的冷钱包。冷钱包很好理解,假设我的手机是一个没有联网的硬件,我需要签名支付的话,只需要拿一根 USB 线和电脑连接一下,就可以签名了,整个过程私钥都不会暴露在联网的环境中。
也就是说如果你想在 PC 浏览器和手机上达到相同的 DApp 体验效果,并且不用频繁切换钱包账号,更不用来回相互转账,目前来看是做不到的。在 PC 端你可以用 MetaMask 钱包,在手机端则需要你在手机钱包中打开才能体验完整的 DApp。想想支付宝和微信支付一站式的跨平台体验,你是否会有这样的念头,难道就没有一款钱包可以解决一站式多平台的签名痛点吗?
更不幸的是 MetaMask 在自己的官方博客上提到,不建议用户把大量的资金放到这类插件钱包中,插件钱包是不安全的。也许此刻你会苦笑,我只是一个普通的小白用户,只想要一款可以多平台签名交易并且安全的钱包,难道这小小的要求都得不到满足吗?别急,我们不妨分析一下目前的现状和可能的解决方案。
如果能有一种钱包可以解决所有平台 DApp 签名问题的话,那么就可以保证体验是一致的,而且移动端钱包的好处是私钥永远保存在手机本地,安全性比浏览器的钱包或插件钱包的安全性都要好;其次用户不需要安装各种各样的钱包来处理来自不同平台交易。
所以如何平衡安全和易用性,以及全平台一致的体验,是多平台签名方案需要解决的问题。这是我们目前看到的行业诉求,于是我们开始调研并且尝试给出我们的解决方案。
手机端扫码方案
现有的互联网应用或许可以给我们提供一些借鉴思路,下图左边是手机端支付宝的支付页面。对于支付宝我们都很熟悉,如果是在手机端用支付宝支付的话,应用会自动唤起支付宝,然后直接在支付宝完成支付流程就可以了。如果是电脑端淘宝网页上支付的话,淘宝付款页面会出现一个二维码,只要打开手机支付宝,扫二维码,在手机里完成支付,然后支付结果就会传到淘宝网,整个支付过程就完成了,体验非常好,而且也非常安全。
图片右边是网易邮箱的服务,以前在 PC 端浏览器上登陆网易邮箱时,需要输入账号和密码,后来网易觉得这样不是很安全,输入账号和密码也比较繁琐,并且万一密码丢失该怎么办?考虑到每个人都有智能手机,而且手机相对个人来说是私密的,安全性很高,所以他们就在浏览器端登陆的时候给出一个二维码,用手机端的邮箱 APP 扫一下二维码,手机端完成验证鉴权,然后 PC 浏览器上的网页邮箱就自动登录成功了。现有互联网产品的解决思路是,既然在浏览器端无法解决保证更好的安全性,那就通过更安全的移动端扫码的方式来弥补这个缺憾。
顺着这个思路往下想,假如你在 PC 浏览器上玩加密猫,现在想下单买一只可爱的猫,过去的方式是必须通过科学上网,安装 MetaMask,创建一个钱包账号,然后从你的 imToken 或其他钱包转一些 ETH 到 MetaMask 钱包,最后签名支付才能购买。那有没有一种方式,直接把加密猫的交易数据通过二维码的方式呈现出来,手机钱包扫一下,在手机上完成整个签名交易流程,然后再把交易数据发到链上,最后把交易结果回传到浏览器网页端,这样整个体验就会非常好。
这个方案我们有想过,但是后来一想,有问题!什么问题呢?
如果普通转账交易是没问题,交易数据比较少,但如果是部署一个合约呢?这是一个普通的合约,功能就说简单的存储和读取数据,data 字段就这么多,换成二维码,你会发现如此密集的二维码,绝大部分的 APP 根本就扫不出来,显然直接扫码这条路是走不通的。
后来我们在公司内部的 Hackathon 尝试了另一个方法,既然数据比较复杂且比较大,不能直接用二维码扫描传到手机,那么能不能用一个服务器作为中继来转发数据呢。还是原来的 DApp,先把复杂的交易数据传到中继服务器上,然后返回给 DApp 一个请求接口,通过这个 HTTP 请求接口客户端就可以访问到完整的交易数据,DApp 拿到请求接口地址后,将请求地址生成一个二维码。
钱包 APP 扫描二维码,获取到请求地址,并从这个请求地址上获取交易数据,钱包用本地私钥完成签名并转发到链上,最后再把区块链返回的交易 hash 发送给中继服务器,由于 DApp 和中继服务端是长连接,DApp 就可以获取到交易 hash, 并根据交易 hash 处理后续的业务流程。
这是一个不错的想法,至少解决了一些问题,但是却引申出了另外的问题。
DApp 的全称是去中心化应用,如果加入中继服务器,那么不管是 DApp 本身还是钱包都会非常依赖中继服务器,一旦服务出现异常或者不可用,整个签名过程就会受阻。一个去中心化应用反而要强依赖中心化服务器,这和区块链的去中心化理念就出现了矛盾。
手机钱包充当服务器方案
为了解决 DApp 和钱包强依赖中心服务器的问题,那么我们就想到了手机能不能成为服务器。如果手机和电脑在同一个局域网内,那么就可以通过 IP 相互直接访问,既然电脑能成为 server,手机也可以是 server。手机作为一个 server,DApp 发交易就是给这个 server 直接发请求,手机拿到交易数据后签名并转发数据至区块链,然后再把链返回的交易 hash 发送给 DApp。这样解决了中心化和去中心化的矛盾,但是有一个问题就是电脑和手机必须在同一个局域网里,要不然没办法无法请求数据。
手机作为一个 server 是一个不常见的方式,通常只有近距离快速传送大文件的时候或者小范围的点对点通信时会使用这种方式,这种方式不适合做扩展,手机换个局域网或者换成 4G 的时候,它的 IP 就会改变,那么 DApp 就需要频繁更改连接的 IP 地址。当你没有办法做到好的兼容的时候,这也许是一个的不错思路。
WalletConnect
行业内有很多团队也在尝试解决这个问题,WalletConnect 是其中一个比较有名的解决方案。它也是使用一个中继服务,而且这个中继服务做的事情比上文提到的要更多。简单来说,首先,DApp 和中继服务器最初会有一次握手,并建立长时间的 session 连接通道,然后 DApp 会生成用于未来加密交易数据的对称密钥,DApp 会把加密后的交易数据发送到中继服务器上,并得到服务器返回的交易数据请求地址。
然后 DApp 将请求地址、对称密钥和 session ID 打包并生成二维码,手机钱包扫描二维码并提取其中的数据请求地址和对称密钥,然后钱包从该接口地址上获取交易数据密文,并用对称密钥解密得到交易数据明文。进而在手机钱包内完成交易确认、签名和转发,最后将从链上得到交易 hash 发给中继服务器。由于 DApp 和中继服务器是长连接,所以中继服务器在拿到交易 hash 后,会推送给 DApp,然后 DApp 就可以根据交易 hash 到区块链上查询交易的执行情况。
WalletConnect 和上文讨论的做法思路是一致的,只不过它更近一步,通过对称密钥对交易数据加密,安全性更好,中继服务器就是一个交易数据转发的地方,二维码则是 DApp 与手机钱包的信息沟通媒介,承载更轻量级的数据。
这个方案中可能还有一个服务器,叫做 Push 服务。如果有 Push 服务,那么 DApp 后续再发送交易数据给中继服务器,就不需要再通过二维码扫描,而是直接将数据推给至 Push 服务,然后由 Push 服务推送消息给手机钱包,手机钱包再去签名并发送至链上,并把交易 hash 告知中继服务。当然如果没有 Push 服务器,整个流程同样是可以走通的,只不过需要手机钱包扫码触发获取交易数据请求,然后再完成后续流程。
需要说明的是 WalletConnect 并不提供公共的 Push 服务,只提供公共的中继服务,对于 DApp 或者钱包运营方来说,需要维护一个中心化的 Push 服务器,虽然体验和安全非常好,但是解决思路有点麻烦。WalletConnect 向以太坊基金会提出了希望将这一套数据规范做成 EIP 协议,目前协议还在讨论中,还没有定下来。
AppLink
还有一个方法,要比上一个方案稍微简单一些。做过移动端开发的朋友可能都知道 DeepLink,或者简单说是 AppLink。
我们都知道在浏览器上打开一个网站链接地址就可以跳转到想要的网页,但是对于智能手机而言,每个 App 都是一个信息孤岛,相互之间是没有一个简单的通讯机制。举个简单的例子,淘宝和微信相互屏蔽,在百度上搜不到微信里的东西。App 之间的信息是割裂状态。因此,Google 和苹果作为操作系统提供方,就希望从操作系统层面上解决这个问题,于是就有了 AppLink。
任何一个 App 只要在 AppLink 服务上按一定的协议规范注册,那么其他 App 就可以通过 AppLink 服务与之连接并通信。比如,我在 PC 浏览器上想要买一只猫,购买页面会呈现出一个交易二维码,我用 iPhone 的系统相机扫描这个二维码,只要这个二维码内容是在我的操作系统 AppLink 中注册过的,那么就可以唤起手机钱包页面,完成后续的签名支付流程。
但是这个服务并没有被广泛使用,原因有很多,最重要的原因是 App 之间不愿共享数据,它们更希望用户一直留在 App 内部,增加用户的使用黏性。而且安卓的碎片化比较严重,国内很多手机厂商更改了操作系统底层代码,这样就没有办法提供很好的一致体验。所以该方案在一些比较小的场景内是可以实现的,不适合所有的场景。这个数据协议也被提交到了以太坊基金会,希望可以建立一个 ERC 标准,目前处于草案过程,并没有达成共识。
MyEtherWallet
最后一个案例很有意思,有个网页版钱包叫 MyEtherWallet,提出了一种通过建立 P2P 安全通道完成签名交易的方案。过去在 MyEtherWallet 上创建一个钱包,私钥、助记词等信息都是由钱包生成,并存在浏览器存储空间中。但是私钥存在网页端其实是不安全的,网页虽然本身有一定的存储功能,但是安全性和手机比还是弱很多,那如何解决这个安全问题呢?
MyEtherWallet 最近出了一个手机 APP 叫 NEWconnect,前段时间开始公测了。他们开发了一个手机端钱包 NEWconnect,它虽然有钱包的很多功能,但是不作为一个独立的钱包角色,而是和网页版钱包配合使用。例如用户在网页端要转一笔 1.5eth 的帐,用户在网页端生成交易,手机端通过 P2P 的方式直接与网页点对点连接,并自动弹出确认交易页面,手机端完成签名交易后,将结果通过 P2P 通信通道回传给网页端,网页端更新并显示交易处理后的数据。
这个方案的体验很好,也很安全。由于是私密的 P2P 通信通道,交易数据不会轻易被盗取,能够完美地解决上面提到的问题。但是该方案同样存在扩展困难的问题,只能在封闭系统中流转数据。P2P 本身就是点对点通信,如果扩展开来,则需要一整套通道建立流程和加密机制,但是这种思路确实值得借鉴。
依然在路上
整个行业到现在也还没有最终的解决方案,我们也在做各种调研和尝试,即使在 Hackathon 上做了一个初级的解决方案,但还不能尽善尽美。行业的诉求和痛点很多人都发现了,并且在尝试积极解决,但是目前整个行业还未达成共识方案。
现在很多区块链服务和互联网服务在体验上还有很多差距,互联网服务是中心化的,有很多中心化的方式去解决体验和安全的问题。而区块链应用是去中心化的,钱包和 DApp 也是去中心化的,如果我们用中继服务去做,就相当于把去中心化的问题用一种中心化的方式来解决,我们先不讨论好与不好,至少不会是最优的解决方案。
安全性也是需要重点考虑的,二维码呈现的交易数据很容易被篡改,中继服务提供的交易请求也很容易被拦截,如果是互联网应用的话,可以通过中心化的方式校验数据,但是对于去中心化的应用,如何做到安全和去中心化的平衡,还需要进一步讨论。
我们可以在 Google Play 和 App Store 上发现大量的钱包软件,彼此之间的体验千差万别,但是始终没有能做到像支付宝那样解决多平台的签名支付问题。为此我们也还在调研和做 MVP 验证,希望未来可以有一套兼顾安全、体验和去中心化的解决方案。