详解使用区块链技术实现安全的二维码网络认证

越来越多的我们在许多应用程序中看到二维码,部分得益于与区块链技术相关的众多项目。之前二维码被视为中国等亚洲国家的独特现象(如微信的QR码),而如今,二维码(QR码)被广泛用于认证,支付,信息交换等。

基本少量的信息传输到使用QR的移动设备可以很简单(必须包括一个库和少量代码)。但是,当涉及到安全性时,基于QR码构建方便和安全的解决方案将变得非常困难。同样在大多数情况下,您还需要一个备用解决方案,例如,在没有第二个屏幕的情况下执行认证。最近了解到的一些项目涉及网上银行登录移动设备支持存储在以太坊区块链上的身份,特细分享:

环境

对于移动开发,我们使用C#和Xamarin表单,在线银行原型是用Ruby-on-rails编写的。移动应用程序用于在以太坊区块链上创建和管理身份。应用程序拥有以太坊秘钥,这是所有的身份属性(姓名,国籍等)和其他方面的证明(如大学的大学文凭)的核心。

目标任务是什么

通常的身份验证是在外部仲裁者的帮助下完成的,直接向消费者发送数据或提供验证,例如OpenID Connect用于登录Google作品。在我们的方案中,这一切都是通过区块链架构提供的非对称加密和签名功能完成的。

在这种情况下,区块链作为一个安全的存储空间(从某种意义上说,那里发布的信息是不能改变的)作为参与方。公共实体可以在那里发布自己的详细信息,例如像网上银行提供他们的名字,以方便用户。这只能通过地址密钥的持有者来完成,并与网站的SSL证书耦合在一起,为用户提供强大的安全性和简单的检查身份信息接收方真实性的方法。

对于用户来说,工作流程是不同的,因为个人信息不能公开,所以只有证明部分正在向区块链发布,信息由一些外部验证者(如我们的银行)提供。

对于用户来说,这允许与不同的ID消费者(例如银行和在线商家)简单地重用现有的身份,而不依赖于单个中央控制的实体。企业也可以从这种模式的简单整合中受益,也可以通过获得验证来与其他实体建立信任关系。

认证程序

认证过程如下:

用户使用ID消费者网站上的移动应用扫描QR码。QR码包含关于ID使用者的信息,URL检索ID使用者公共密钥的位置,安全性和属性要求的信息。

移动应用程序加载ID使用者的公钥,安全密钥和URL以发布身份数据。

移动应用程序请求用户批准与以太坊地址标识的ID消费者共享身份详细信息。底层区块链协议为该地址提供验证,用户可以确定身份数据接收者的可信度。

身份数据由用户的以太坊密钥签名,并使用ID消费者公钥的非对称加密进行加密。

加密的有效信息与安全密钥一起发送给ID消费者。

ID消费者使用安全密钥来解密私钥,该私钥会被加密并且特定于该登录会话。

当私钥被恢复时,消费者使用它来解密有效信息。

解密的有效信息中的签名用于恢复签署者以太坊公钥和地址。如果地址匹配有效信息中的地址,我们可以假设成功登录。

QR码由以下代码生成。我们正在为登录会话建立一个唯一的标识符,并指定身份信息的接收者。由于QR码的使用寿命较短,因此我们还必须包含时间戳,以便移动应用在请求过期时能够显示倒数计时器。

def qr_code( root_url ) params = { by: "0x5ddA491Bc5Fc1C7dC5A3B90078eA24d3b1407482", id: self.uuid, at: Time.now.to_i, eu: crypto_url(root_url), en: true, v: 1, }.to_query qr_string = "kycex://auth/request?#" puts "INFO: QR is: #" puts "INFO: crypto URL is: #" qr_string end

URI模式kycex是指由移动应用程序注册的模式,以便能够处理来自任何QR码阅读器应用程序的身份验证请求。移动应用程序然后使用eu(加密URL)参数来检索有效负载加密的公钥。

def generate_key nonce = SecureRandom.uuid rsa_key = OpenSSL::PKey::RSA.new(2048) if rsa_key == nil puts "ERROR: could not generate session encryption key!" return end cipher = OpenSSL::Cipher::Cipher.new('des3') if cipher == nil puts "ERROR: could not encrypt key!" return end self.privkey = rsa_key.to_pem(cipher, nonce) self.pubkey = Base64.encode64(rsa_key.public_key.to_pem) self.nonce = nonce end

加密URL生成一个新的RSA公钥/私钥对。私钥使用3DES对称加密进行加密并存储在本地。公钥被返回给移动设备,而在本地丢弃。这确保了如果本地存储被破坏,私人密钥不能被清楚地读取,并且在到达ID消费者之前不能获得对加密的有效载荷的访问。使用新的RSA密钥对进行每次认证也会提高安全性,因为重复使用同一个密钥对可能导致安全风险,例如违反一个会话会影响其他人。我们还在下面使用不同的密钥进行签名处理,因为重复使用相同的密钥进行签名和加密操作肯定会降低整体安全性C#中的RSA加密部分是使用BouncyCastle nuget包完成的

可以使用RSA加密加密的数量由选定的密钥长度定义。在我们的例子中,这是2048位,最大输入块大小为245字节。当使用PKCS1 OAEP编码时,每个块将转换为256字节,因为编码增加了控制结构,并且由于熵增加使得密码更加健壮,从而增加了总体安全性。如果明文块小于245字节,则通过编码将其填充到正确的所需长度。这就是密文长度始终是n×256个字节的原因。在Ruby的解密方面,可以使用相同的步骤(以相反的顺序)

# Check if this session has stored encrypted private keyif self.privkey.nil? self.privkey.empty? raise "Session request in invalid state"end# We need a decryption key for our private keyif nonce.nil? nonce.empty? raise "Session request in invalid state"end# Use builtin OpenSSL API binding to initialize encrypted keyrsa_key = OpenSSL::PKey::RSA.new(self.privkey, nonce)if rsa_key.nil? raise "Session key decryption failed"end# HTTP POST contains base64 encoded payload# p now contains binary cyphertextp = Base64.urlsafe_decode64(payload)# As we know the key length and corresponding block size we set this manuallybs = 256i = 0json = ""while (i < p.length) begin # Decrypt each block individually using the correct encoding and padding json true)

可以看出,区块链技术为以安全为重点的应用程序提供了良好的基础,因为安全方面已经内置于协议本身中。另一方面,尽管区块链已经存在了一段时间,但令我惊讶的是,对于以太坊和比特币来说,椭圆曲线(EC)secp256k1密钥的工作明显缺乏良好的工具和库。一个很好的例子就是以太坊的签名验证 : 至少我没能找到一个适合Ruby的应用,并且不得不使用一个Bitcoin gem,这个Bitcoin gem是基于比特币基础的3年前的libsecp256k1实现。另一个潜在的改进领域是用于小型有效载荷的基于EC密钥加密的库。尽管从理论上讲,OpenSSL没有高级的包装器,至少在Ruby中是这样做的。

另一方面,由区块链基础设施支持的单一数字身份可以是具有共享令牌的传统系统的主要优势。虽然目前整体采用率很低,每个人似乎都对玩密码市场更感兴趣,但我发现在区块链的帮助下,分布式透明身份验证和身份数据共享的潜力巨大。

欢迎关注国内权威 区块链行业分析公众号:中本区块

  • 发表于:
  • 原文链接http://kuaibao.qq.com/s/20180207G10IVX00?refer=cp_1026
  • 腾讯「云+社区」是腾讯内容开放平台帐号(企鹅号)传播渠道之一,根据《腾讯内容开放平台服务协议》转载发布内容。
  • 如有侵权,请联系 yunjia_community@tencent.com 删除。

扫码关注云+社区

领取腾讯云代金券