有时我们需要让用户以电子方式签名。人们通常会明白,不知何故把你的手写签名放在屏幕上。取决于管辖范围,这可能是罚款,或它可能不足以仅仅存储图像。例如,在欧洲,么是电子签名。正如法律文本所预期的那样,该定义相当模糊:
“电子签字”是指与其他电子形式的数据相连或在逻辑上与其他电子形式的数据相联系并为签字人所用的电子形式的数据;
是的,再读几遍,再说几遍“Wat”,让我们来讨论一下这意味着什么。基本上意味着什么。从技术上来说,将所绘制签名的图像(例如,使用html画布)附加到数据上是可以接受的,这可能还算在内。
但是当我们接触到更具体类型的电子签名--先进和合格的电子签名时,情况会变得更好一些:
先进的电子签字应当符合下列要求:
(A)它与签字人有着独特的联系;
(B)它能够识别签字人;
(C)是使用电子签字制作数据制作的,签字人可在高度自信的情况下在其单独控制下使用;和
(D)它与与之签署的数据相关联,其方式使数据中的任何随后变化都是可察觉的。
从技术意义上看,这似乎是一种适当的“数字签名”--例如,使用私钥进行签名,使用公用钥匙来验证签名。“合格”签名需要由基本上是受信任的证书颁发机构的合格提供者颁发。放置合格签名的密钥必须在安全设备(智能卡和HSM)上颁发,这样除了所有者之外,任何人都可以访问私钥。
https://www.jianshu.com/p/4f81daf4fbaa
但高级签名和合格签名之间的法律区别并不完全清楚--该条例明确规定,非合格签名也具有法律价值。在浏览器中使用合格的签名(使用智能卡)是一种可怕的用户体验--在大多数情况下,它都是通过Java Applet完成的,而Java Applet现在基本上只在InternetExplorer和Firefox的特殊版本上工作。其他选择包括桌面软件和处理签名的本地服务JWS应用程序,但智能卡目前是一个很大的问题,也是一个不相干的话题。
那么,我们如何允许用户“放置”电子签名呢?我有一个想法,这可以完全使用WebCryptoAPI来完成,而这些API现在或多或少地在浏览器中得到了支持。设想如下:
- 让用户输入一个密码,以便进行排序。
- 从密码派生密钥(例如使用PBKDF 2)
- 用派生键对用户提交的表单内容进行签名。
- 将签名与表单数据的其余部分一起存储。
- 可以选择地存储派生密钥以进行验证。He2buf、buf2hex和str2ab函数都是实用程序(遗憾的是,在js中这是不标准的)。
尽管代码有点冗长,但代码所做的工作很简单。所有的操作都是用承诺和“那么”链接起来的,老实说,写和读都是一件很乏味的事(但我想这是不可避免的):
https://www.jianshu.com/p/34b984bde996
- 密码作为原始密钥加载(在转换到数组缓冲区后)
- 使用PBKDF 2导出密钥(具有100次迭代)
- 密钥用于对用户填写的内容执行hmac“签名”。
- 签名和密钥被存储在(本例中的UI中)
- 然后,可以使用数据、签名和密钥对签名进行验证。
您可以在这里测试它:
https://www.wenjuan.com/s/UZBZJvoeFe/
储存签字应足以完成“电子签字”的定义。事实上,这是一个只有用户才知道的秘密密码,这甚至可能意味着这是一个“先进的电子签名”。存储派生密钥是有问题的--如果存储它,就意味着您可以代表用户“伪造”签名。但是不存储意味着您无法验证签名--只有用户才能验证。根据用例的不同,您可以选择一个或另一个.
现在,我不得不承认,我尝试从密码(RSA和ECDSA)派生一个非对称密钥。WebCryptoAPI不允许开箱即用。因此,我尝试使用demveBits()“生成”密钥,例如为RSA设置“n”和“d”值,为ECDSA设置x、y和d经过一番搜索)。但是我失败了--你不能将任何值指定为import Key参数,约束在任何地方都没有文档记录,除了低级的算法细节,这有点超出了我的实验范围。
我们的目标是,如果我们只从密码中派生私钥,那么我们可以很容易地从私钥(反之亦然)派生出公钥--然后我们存储公钥以进行验证,私钥仍然是真正的私有密钥,这样我们就不能伪造签名。
我必须在这里添加一个免责声明,我意识到这不是很安全。首先,从密码派生密钥在许多情况下都是有问题的。但是,在这种情况下(放置签名),就可以了。
顺便提一句--使用WebCryptoAPI是很乏味的。也许是因为还没有人真正使用过它,所以谷歌搜索错误基本上会给你铬的源代码和其他东西。这就像是一个未知的领域(尽管文档和示例足以让您开始工作)。
用这种方式做电子签名是否有用,我不知道。我实现它是为了一个实际有意义的用例(党员声明签名)。不管它是否比画布上的手绘签名更好--我认为是这样的(除非你从图像中得到密钥,在这种情况下,手写的签名会因为更高的熵而更好)。