以太坊有一个很是强大的JavaScript生态系统。有一些很棒的开源项目,好比ethereumjs-util
,它提供了一个用以太坊账户签名的即插即用功能。php
JavaScript的一个缺点是,在许多领域,它带来了安全问题。一个这样的安全风险是显而易见,这是因为我努力在EthTools.com
上实现持久性认证(仍然是一个正在进行的被警告了的工做)。html
利用开源项目(如ethereumjs-util)来签署任意的数据消息是至关容易的。然而,不容易的是告诉服务器有人已经成功地验证了某账号的全部权。node
固然这也不是绝对正确的,你也能够很容易作到这一点。简单地构建一个简单的API端点,并在成功认证后向其发出请求。git
真正的问题是,建立一个“假”请求并将其发送到上述(易于识别 - 只需在控制台中查看)端点很是容易。 我能够轻松发出请求,说我已经验证了任何账户的全部权。github
凭借尖端技术……特别是处理“真实价值”的技术,尤为重要的是安全性体现出了它应有的重要性并被重视,特别是在历史上出现各类被利用的攻击的状况下。web
并且即便是在初期,以太坊也吸引了最优秀的人——那些知道在作什么的人。若是有安全漏洞,有人会找到它。api
如今。。虽然能够确保AJAX请求和伪造更难,但几乎不可能使交易100%的安全。我须要另外一种方式。数组
我最终解决的方法是选择最简单的服务器端认证方式。缓存
在客户端中与区块链交互的一件大事是,在任何状况下,任何人都能清楚地看到你在作什么。他们能够自信地知道你没有把他们的私人钥匙发送给别人。怎样?他们能够查看控制台并查看每个发出的请求。安全
若是一个服务在任何地方POSTing
个人私钥,我会很是担忧。
在咱们实现的认证流中,用户能够看到咱们没有在任何地方发送任何数据——全部的东西都是在客户端中完成的。
遗憾的是,个人身份验证方案中确实须要POSTing
数据。但也不用担忧(有些人可能不一样意)。
咱们POST
身份验证的公钥到咱们的API端点。虽然你不能用服务器上的公钥来验证咱们所作的事情,但咱们并无用你的公钥作任何恶做剧——这就是为何它是公开的。
在服务器上,咱们使用提交的公钥来验证提交的签名是由具备相应私钥信息的人建立的。这里要明确指出,咱们不知道你的私钥,但椭圆曲线加密容许咱们经过简单地使用公钥来验证签名是不是使用它建立的。
在ethereumjs-util和solidity中,ecrecover
方法是前提,除非这些工做分别在客户端和区块链中。
在以太坊论坛上,chriseth给出了ecrecover
的如下有用解释:
ecrecover
的思想是,能够计算对应于用于建立ECDSA
签名的私钥的公钥,这两个额外的字节一般是由签名提供的。签名自己是椭圆曲线点R和S的两个(编码),而V是恢复公钥所需的两个附加位。
这也解释了为何返回类型是地址:它返回对应于恢复的公钥(即其sha3/keccak的哈希)的地址。这意味着要实际验证签名,检查返回的地址是否等于相应的私钥应该已经签署哈希的那个地址。
咱们但愿在服务器上有相同的功能。
注意:Solidity的ecrecover
返回一个地址,而ethereumjs-utils的ecrecover
返回一个公钥。
注:研究期间,我发现了一些有趣的StackExchange的问题主题。这些内容以下:
web3.js API文档还提供了一些关于ecrecover
的参数的看法:
After the hex prefix, characters correspond to ECDSA values like this: r = signature[0:64] s = signature[64:128] v = signature[128:130] Note that if you are using ecrecover, v will be either "00" or "01". As a result, in order to use this value, you will have to parse it to an integer and then add 27. This will result in either a 27 or a 28.
[EthTools.com]是创建在Phalcon PHP框架之上的。
没有真正意义上的以太坊PHP社区,PHP在处理数值表示方面有其缺点。
固然,椭圆曲线密码的问题是极其复杂的,而我对它也缺少已经掌握的可用知识。
在大量的资料查询研究和大量的开发调试以后,我成功地实现了PHP中的ecrecover
功能。
虽然我知道如何作到这一点,我写了一些“笔记”,我整理和包含在下面的内容,但愿能帮助别人了解正确的方向。
个人行动逻辑是使用ethereumjs-util
,使用已知的以太坊私钥签署交易。而后,我会模仿PHP中的ecrecover
方法的代码路径,而后像宏播放同样执行,直到从签名返回的输出公共密钥与原始签名账户匹配。
因此…
在Node中,缓存 Buffers 是无符号8位整数的数组。 digits 是它们的10进制(十进制)表示。
8位就会有2^8=255个十进制选项。这些整数是来自UTF-8字符集的字符的数字编码表示。
Node利用这些缓存来进行这些计算所需的排序的数据操做。
在服务器上,咱们有不一样的字符串(消息哈希和签名),可是PHP不知道这些字符串中的字节是base 16 numerical表示(十六进制)。
每一个字符都是一个“小写”,它须要4个字节来表示(容许十六进制字符是0—9和A—F)。
这样,8位数据是两个十六进制字符。
在Node中,将字符串“61BF09”转换为一个buffer,经过将两个小写的集合转换成它的十进制形式。
要在PHP中执行等效,咱们执行以下的操做:
$r_byte_array = unpack('C*', hex2bin($r));
咱们调用hex2bin
,它将十六进制字符串(不含0x)转换为二进制表示(base 2)。经过调用这个方法,咱们隐式地说明初始格式是十六进制。
unpack而后将字符串转换为代码中的数组——咱们的Buffer等价物。
最初PHP只是认为字符串是UTF-8。若是咱们不先调用hex2bin
,第一个int是54,效果是这样:
这是由于unpack
只是将UTF8中的第一个字节(54)转换成二进制代码(6),64个字符=64个代码点。
当咱们告诉unpack
咱们处理十六进制时,它将每一个两个字节的十六进制集合(每一个表明4位数据的字符)转换为它的十进制表示。61(0x61)变为97。咱们的64个字节十六进制字符串变成32个8位整数,效果是这样:
你能够经过使用这个转换器来看这些不一样的表示。
如今,你就有一个符合要求而且已经格式化了的消息哈希和签名表示,“你能够做弊了”。
我比较懒和喜欢自作聪明。也就是说,让我试图充分理解、欣赏和实施secp256k1
椭圆曲线是根本不会发生的。此外…何苦?这是一个不须要从新发明的轮子。
我发现了一些与secp256k1
有关的php库。例如:
我最终使用了全部三个库的组合,我喜欢知道我在使用什么,而且基本上(至少)理解我正在向服务器推送什么。上面的库是至关丰富的、复杂的,我只是简单提取我须要的相对简单的功能。
在花了大量的时间来了解我正在作的事情以后,我终于成功地实现了我想要达到的目标——我已经成功地验证了以太坊客户端中建立的签名是来自个人一个特定的私钥。
当我第一次爬进这个rabbit hole
的时候,我会继续实施我所想到的功能。
注意事项。2018年又我写了第二篇文章,详细介绍了我如何验证PHP先前签署的消息的有效性。(注:后面也会翻译给你们)
若是你们在学习用php开发以太坊那咱们推荐这个教程:
php以太坊,主要是介绍使用php进行智能合约开发交互,进行帐号建立、交易、转帐、代币开发以及过滤器和事件等内容。
汇智网原创翻译,转载请标明出处。这里是原文