具有 HMAC 的安全远程密码协议 (SRP6a) 符合您的要求
以下假设您的 API 是浏览器到服务器的,因此 JavaScript 到 PHP 不是仅使用 PHP 的服务器到服务器。SRP 将同时适用于这两种方案,但下面的答案讨论了浏览器到服务器库。
使用安全远程密码协议对 API 的用户进行身份验证,这会产生创建强会话密钥的副作用。然后,您可以使用共享的强会话密钥,通过 HMAC 对 API 请求和响应进行签名。
RFC5054 使用 SRP 而不是公钥来创建共享会话密钥来加密 TLS 流量。OpenSSL中有一个实现。这表明 SRP 身份验证是完全安全的公钥替代品,可以创建安全的共享密钥。恕我直言,使用SRP可以更方便地解决您的问题。
Thinbus SRP库是一个JavaScript SRP库,它具有对PHP服务器进行身份验证的演示。PHP 演示没有显示使用共享会话密钥,但一旦身份验证协议完成,它只是在服务器和浏览器中。默认的 Thinbus 配置会产生 256 位共享密钥。您可以将此功能与 HMAC 一起使用,请参阅下面有关使用签名 JSON 的脚注 1。$srp->getSessionKey()
client.getSessionKey()
它是如何运作的
注册流程为:
- 客户端 API 注册表单在客户端使用 JavaScript 生成一个随机 API 密码,该密码不会传输到服务器。这被保存到浏览器本地存储中,并显示给用户,要求他们打印出来并保留备份。
- 密码被提供给 Thinbus SRP 客户端 JS 库代码,该代码输出客户端盐和密码验证器。
- 盐和验证器将发布到服务器并保存在该客户端的数据库中。通常,Thinbus建议您通过使用HTTPS将验证程序发送到服务器来隐藏验证程序,以防止暴力攻击来恢复密码。如果您使用的是随机生成的密码,只要是典型的软件许可证密钥,那么您可以通过HTTP传输验证程序。见下文脚注2。
API 使用流将从客户端的 SRP 身份验证开始,该身份验证具有生成会话密钥的副作用。请注意,所有这些都在 Thinbus 演示代码中作为“标准用法”进行,但此处进行了解释,以提供 STP 身份验证的工作原理。此身份验证协议显示在 thinbus 页面的序列图中,并在在线演示中运行:
- 客户端 javascript 从浏览器本地存储加载 API 密码。
- 客户端 AJAX 从服务器获取客户端盐和服务器随机一次性编号。
B
- 客户端javascript生成一个一次性数字,然后使用密码,salt和两个一次性数字来生成会话密钥,并使用两个一次性数字进行哈希处理,以创建密码证明,该密码证明与其随机一起发布到服务器。
A
K
M
A
- 服务器使用注册时保存到数据库的密码验证器、客户端盐和两个随机数来计算会话密钥,然后确认客户端发送的密码证明是否良好。如果这一切都很好,它会将自己的证据发回给客户端。此时,客户端已使用 STP 作为密码的零知识证明进行身份验证。
K
M
M2
- 客户端根据其计算进行检查。如果一切正常,双方都有一个共享的秘密,这是一个从随机派生的一次性256位会话密钥,没有中间人可以知道。
M2
K
A
B
- 所有 API 请求和响应都可以使用共享密钥进行 HMAC 签名,并在另一端进行验证。
以上所有内容都在Thinbus的PHP演示中进行了介绍,减去最后实际调用以拥有一个可用于使用HMAC对事物进行签名的密钥。$srp->getSessionKey()
鉴于SRP将密码身份验证替换为密码的加密零知识证明,令人惊讶的是,默认情况下并非所有开发人员都使用它。它还为API签名生成共享会话密钥的事实只是一个额外的好处。
脚注1:大多数 API 更愿意发布一个包含所有数据的 JSON 值。这是因为JSON很简单,但功能更强大,在PHP和JavaScript中内置了API,可以将对象转换为字符串并再次返回。正如@dbrumann在注释中指出的那样,有一个用于签署JSON的标准,即JWT。Google建议这里有PHP和JavaScript的库。因此,如果您升级到传递一个 JSON 输入值并为 API 中的每个命令返回一个 JSON 输出,则可以使用 JWT 库对 API 的 JSON 输入和输出进行签名和验证。JWS算法之一是“JWSAlgorithm.HS256 - HMAC with SHA-256, 256+ bit secret”。这些库将整理实际签名和验证的机制,因此您不必编写该代码并担心可能的安全错误。
脚注2:Thinbus的建议是通过HTTPS将密码验证器传输到服务器,以保持验证程序的机密性。这是为了防止拦截然后对密码验证器的离线字典攻击以恢复密码(即密码被盐渍到验证器中,因此您需要通过验证器生成代码运行16G破解密码字典与用户盐以找到匹配项)。通过API的使用,browser window.crypto API可以生成一个真正随机的“API密钥”。通常,Windows 键是 16 个大写字母,以格式设置为 XXXX-XXXX-XXXX-XXXX。检查GRC密码搜索空间页面,它说随机的16个字母大写密码的大小需要政府14年才能彻底搜索。鉴于这种估计,您可以在没有加密的纯HTTP上安全地传输为如此长的随机密码生成的密码验证器,因为没有人会通过验证器生成算法(使用随机客户端盐,因此无法预先计算)来找到匹配项来恢复客户端API密码。