电子签名要求

时间:2017-04-15 06:31:03

标签: php mysql electronic-signature

Hello Stackoverflow社区,

我对电子签名有困难,特别是如何在技术要求方面应用新加坡法律。

根据法律规定,如果签名是:

,新加坡会接受电子签名
  • 使用它的人独有;
  • 能够识别此人;
  • 以某种方式或使用以下方式控制的方式创建 使用它的人;和
  • 链接到与之相关的电子记录,如果记录被更改,电子签名将无效。

我们可以通过HTML5画布制作电子签名,然后将其保存为数据base64字符串。这意味着第1点,第2点和第3点都没问题。

第4点出现问题,我们确实可以将签名和数据合并到加密字符串中,但是,由于我们有签名和数据,我们可以编辑数据并创建新字符串:

|id|name|price|signature|final_hash|
------------------------------------
|12|test|40000|data:base|3edcde4642|

所以我们考虑了另一种方法,即将一些我们不知道的参数混合到final_hash中,例如签名者的IP地址,他/她的用户代理......但是,由于我们不保存这些值,这意味着我们以后无法检查某些值是否被修改。

我们被困的地方,您对如何做到这一点有任何想法吗?对我来说,似乎无法满足既能检查数据是否被修改以及以后无法修改数据,但我当然可能错了。

非常感谢你的帮助!

1 个答案:

答案 0 :(得分:3)

注意:我使用术语"文档"引用你要签署的任何内容。

一些误解

  • 首先,您使用HTML5画布或类似方法获得的不是签名而是指纹。我的意思是它识别客户端,但它不能签署文件(至少不是单独的)。两个警告:

    1. 指纹属于浏览器,而非用户。
    2. 会有碰撞。事实上,为了保护隐私,推动使用指纹识别浏览器更加困难,主要是因为公司可以使用指纹识别来跟踪你而不需要使用cookie。
  • 您不应通过将指纹连接到数据来进行签名。这不是签名,即salt,也不是盐的最佳方法。

顺便说一下,ClientJS是创建浏览器指纹的好工具

您的要求

  
      
  1. 使用它的人独有;
  2.   
  3. 能够识别此人;
  4.   

这些要求拼写"识别"。这意味着你需要一个人的身份证。

  
      
  1. 以某种方式或使用手段独立控制   使用它的人;和
  2.   

此要求拼写"身份验证"。这意味着您需要验证人员是否是他们声称的人。你可能已经看过这个理论,你通过以下方式做到这一点:a)人 (即生物识别)的东西b)人知道的东西(即密码)或c)人有的东西(即访问权)到电子邮件帐户,手机等...)。

令我困扰的是,您似乎正在使用浏览器指纹进行身份识别和身份验证。这可能会使伪造请求看起来太容易成为另一个用户。

通常,在这种情况下您要做的是使用用户名和密码进行传统的身份验证过程,然后发出cookie。为什么要避免这种情况?

  
      
  1. 链接到与之相关的电子记录,如果记录被更改,电子签名将无效。
  2.   

此要求法术"签名"。这可能意味着电子记录将是公开的,我们希望有防止伪造的保护。

  

似乎无法满足能够检查是否有数据被修改以及以后无法修改数据

一般的想法是在修改文档时使签名无效。如果要将修改设为官方,则需要创建新签名。

为了防止第三方从修改后的消息中创建签名,您需要添加一些密钥。现在,这提出了两个问题:

  1. 第三方是否应该验证签名?如果他们应该,你需要一个asymettric算法。

  2. 文件是否应该受到保护(或者有权访问服务器的人)?如果它们应该受到保护,则表明您需要为每个用户提供一个秘密。最简单的解决方案是拥有密码。

  3. 不对称解决方案

    要在PHP中实现非对称解决方案,我建议使用phpseclib

    关注他们的example to create a key pair

    include('Crypt/RSA.php');
    $rsa = new Crypt_RSA();
    $pair = $rsa->createKey();
    $privatekey = $pair['privatekey'];
    $publickey = $pair['publickey'];
    

    代码将使用从服务器收集的熵来生成密钥对。

    然后你可以用它来做简单的RSA signature and verification

    include('Crypt/RSA.php');
    $rsa = new Crypt_RSA();
    $rsa->loadKey('...'); // private key
    $plaintext = '...';
    $signature = $rsa->sign($plaintext);
    
    $rsa->loadKey('...'); // public key
    echo $rsa->verify($plaintext, $signature) ? 'verified' : 'unverified';
    

    如果您需要验证客户端上的签名,可以使用jsrsasign

    对于您的用例,您只需要一个密钥对用于服务器。这里的概念是服务器正在签署文档。如果签名匹配,则表示指纹正确。

    无论哪种方式,您都应该保密私钥(不要将其发送给客户端),并且您可以与需要验证签名的人共享公钥。

    使用此服务器,服务器可以签署标识用户/客户端的文档(例如,包括指纹),并发布文档和签名。该文档将是完全可读的(它没有加密),但如果有人修改它,签名将不再有效。

    要验证签名,他们需要公钥。但是,公钥对于创建虚假签名没有用处,他们需要获取私钥。

    对称解决方案

    对称算法的主要优点在于性能。对称算法的缺点是你需要密钥来验证它。

    因此,如果您需要第三方验证签名(或者即使您需要在客户端进行验证),您也会暴露用于创建签名的密钥。

    在这种情况下,签名更容易实现。使用密钥签署使用hash_hmac。要验证签名,请重复此过程并将其与您获得的签名进行比较。

    每个用户的密钥

    我不确定您是否正在尝试保护自己的数据。也就是说,如果您的目标是阻止您(或您的团队/或管理服务器的任何人)篡改数据。

    如果这是您想要的,您可以使用密码保护您的密钥。对于非对称解决方案,phpseclib允许您设置用于加密私钥的密码(因此需要能够签名)。对于对称解决方案,您可以直接使用密码作为密钥。

    如果您想要的是从指纹生成该密码,您可以使用密钥派生函数执行此操作...但是,请记住,fingerprint collisions会有key derivation function,并且具有唯一的浏览器指纹可以是被视为隐私问题。

    密钥派生函数

    您可以使用pepper从外部输入(浏览器指纹,用户密码等)获取加密密钥。

    从最差到最佳选择:

    • 截断指纹大小。 不要这样做。这浪费了指纹的熵。它很可能发生碰撞。
    • 哈希指纹。 不要做任何事。任何能够获取指纹并知道你使用的哈希值的人都可以获得密钥。
    • 哈希与message authentication code连接的指纹(每个人使用相同的盐)。 仍然不好
    • 用盐连接指纹(每个人都是独一无二的)。许多人说这是第一个理智的选择。但是,你应该记住使用一个好的散列算法。
    • 使用基于散列的hash_hmachash_hkdf。对我来说,这是第一个理智的选择。实际上没有什么可以将连接的哈希值更改为对hash_hmac的调用。此外,它还可以保护您免受哈希算法(已知或待发现)的部分原像漏洞的影响。
    • 使用专用密钥派生算法。在标准的PHP函数中,我建议hash_pbkdf2或{{3}}。

    注意:有时人们(包括过去的我)将这些密钥派生函数称为哈希函数。原因是当你使用它们时,你不会直接调用你的常规哈希函数,它们给你的东西在技术上是一个哈希。然而,实际上,它们不是哈希算法;它们是基于散列构建的算法......事实上,使用它们的参数之一就是内部使用的散列函数。