如何用公钥和私钥

时间:2015-10-26 14:57:59

标签: php api security hash

我试图设计一个小api但是我有点坚持如何保护api。我已经阅读了一些关于如何执行此操作的文章:登录并检索apikey然后使用此apikey散列一些值并将散列字符串与请求一起发回,因此可以在服务器级别再次完成。 / p>

这是一个好方法还是这样做很危险?

如果没有错过理解,为了避免中间的人,我可以将请求网址添加到将被散列的变量,或者不是合适的方式

此外,我的大脑仍然坚持如何使用时间戳来避免使用相同的数据向同一个网址发出大量请求。

对不起,如果我的问题被问了1000次。不过我现在已经阅读了一些文章,但我仍然不清楚我的小api会怎么样。

根据我的阅读和理解,这应该是方法。

  1. 公钥存储在应用程序中,以便用户或应用程序登录。
  2. 服务器在访问此特定用户时为其创建私钥。或者它应该始终相同还是由人创建的静态值?
  3. 用户使请求发送带有签名的hash_hmac(某些值+私钥);
  4. 服务器检查这些值是否正确,并通过从发送的值创建相同的哈希来实现。
  5. 如果服务器生成相同的哈希,则该请求有效,然后可以执行。
  6. 这是他们的出路还是我在这里错过了一些市长的事。
  7. 对于hasing数据是一种创建哈希的好方法吗?

    $l_sPrivateKey = 'something returned by database when user loged in';
    $l_aData = array();
    
    foreach($_POST as $key => $value){
     if($key == 'signature') continue;
     $l_aData[$key] = $value;
    }
    
    //This should then be the same as $_POST['signature'];
    hash_hmac('sha256',serialize($l_aData),$l_sPrivateKey, false); 
    

    您的意见将不胜感激。 亲切的问候和提前谢谢

1 个答案:

答案 0 :(得分:2)

使用HMAC的安全远程密码协议(SRP6a)符合您的要求

以下假设您的API是浏览器到服务器,因此JavaScript-to-PHP不是仅使用PHP的服务器到服务器。 SRP将适用于这两种方案,但下面的答案讨论了浏览器到服务器库。

使用Secure Remote Password协议对API的用户进行身份验证,这会产生创建强会话密钥的副作用​​。然后,您可以使用共享强会话密钥使用HMAC对API请求和响应进行签名。

RFC5054使用SRP而不是公钥来创建共享会话密钥来加密TLS流量。有一个implementation in OpenSSL。这表明SRP身份验证是公钥创建安全共享密钥的绝对安全替代品。恕我直言,使用SRP更方便解决您的问题。

Thinbus SRP库是一个JavaScript SRP库,它有一个对PHP服务器进行身份验证的演示。 PHP演示没有使用共享会话密钥显示,但是一旦身份验证协议完成,它就只是服务器上的$srp->getSessionKey()和浏览器中的client.getSessionKey()。默认的Thinbus配置产生256位共享密钥。您可以将此与HMAC一起使用,请参阅下面的脚注1,了解如何使用签名的JSON。

如何运作

注册流程为:

  1. 客户端API注册表单在客户端使用JavaScript生成随机API密码,该密码不会传输到服务器。这将保存到浏览器本地存储中并显示给用户,要求他们将其打印出来并保留备份。
  2. 密码提供给Thinbus SRP客户端JS库代码,该代码输出客户端salt和密码验证程序。
  3. salt和verifier将发布到服务器并保存在该客户端的数据库中。通常,Thinbus建议您使用HTTPS将验证程序隐藏起来,以便将验证程序发送到服务器,以防止强力攻击恢复密码。如果您使用随机生成的密码,只要是典型的软件许可证密钥,那么您可以通过HTTP传输验证程序。见下文脚注2。
  4. API使用流程将从客户端的SRP身份验证开始,该身份验证具有生成会话密钥的副作用​​。请注意,所有这些都在Thinbus演示代码中作为"标准用法"但这里解释的是介绍STP身份验证的工作原理。此身份验证协议显示在thinbus page的序列图中,并在联机演示中运行:

    1. 客户端javascript从浏览器本地存储加载API密码。
    2. 客户端AJAX从服务器获取客户端盐和服务器随机一次性编号B
    3. 客户端javascript生成一次性号码A,然后使用密码,salt和两个一次性号码生成会话密钥K,并使用两个一次性数字哈希创建一个密码证明M,将其与随机A一起发布到服务器。
    4. 服务器使用在注册时保存到数据库的密码验证程序,客户端盐和两个随机数来计算会话密钥K,然后确认客户端发送的密码证明M是好的。如果这一切都很好,它会将自己的证明M2发送回客户端。此时,客户端已使用STP作为zero-knowledge proof密码进行了身份验证。
    5. 客户端根据其计算检查M2。如果一切都很好,双方都有一个共享秘密K,这是一个一次性的256位会话密钥,来自随机AB,没有中间人可以切实可行知道。
    6. 所有API请求和响应都可以使用共享密钥进行HMAC签名,并在另一方进行验证。
    7. 以上所有内容都包含在Thinbus的PHP演示中,减去实际上在末尾调用$srp->getSessionKey()以获得可用于使用HMAC签名的密钥。

      让SRP用密码的零知识密码证明替换密码验证令人惊讶的是并非所有开发人员都默认使用它。它还为API签名生成共享会话密钥这一事实只是一个额外的好处。

      脚注1: 大多数API都希望发布一个包含所有数据的JSON值。这是因为JSON很简单但功能更强大,在PHP和JavaScript中都内置了API,可以将对象转换为字符串并再次返回。正如@dbrumann在评论中指出的那样,签署JSON的标准是JWT。谷歌建议这里有PHP和JavaScript的库。因此,如果您升级为传递一个JSON输入值并为API中的每个命令返回一个JSON输出,则可以使用JWT库来签署和验证API的JSON输入和输出。其中一个JWS算法是" JWSAlgorithm.HS256 - HMAC与SHA-256,256+位密码"。这些库将理清实际签名和验证的机制,因此您不必编写该代码并担心可能存在的安全漏洞。

      脚注2: Thinbus的建议是通过HTTPS将密码验证程序传输到服务器,以使验证者保密。这是为了防止拦截然后对密码验证程序进行离线字典攻击以恢复密码(即密码被加密到验证程序中,因此您需要通过验证程序生成代码运行16G crackstation password dictionary并使用用户salt来查找一场比赛)。使用API​​时,浏览器window.crypto API可以生成真正随机的" API密钥"。通常,Windows键是向用户显示的16个大写字母,格式为XXXX-XXXX-XXXX-XXXX。检查GRC password search space page它说一个随机的16字母大写密码,这个大小将需要政府14年才能彻底搜索。鉴于这种估计,您可以安全地通过普通HTTP传输为这么长的随机密码生成的密码验证程序,而无需加密,因为没有人可以通过验证器生成算法(使用随机数)运行如此多的密码猜测。客户端盐所以无法预先计算)找到匹配来恢复客户端API密码。