如何用公钥和私钥保护一个小的PHP api

Ias*_*son 15 php security api hash

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

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

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

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

如果我的问题被问了1000次,我很抱歉.不过我现在已经阅读了一些文章,我仍然不清楚我的小api会走哪条路.

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

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

对于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); 
Run Code Online (Sandbox Code Playgroud)

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

sim*_*905 3

具有 HMAC 的安全远程密码协议 (SRP6a) 满足您的要求

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

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

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

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

怎么运行的

注册流程将是:

  1. 客户端 API 注册表在客户端使用 JavaScript 生成随机 API 密码,该密码不会传输到服务器。该信息被保存到浏览器本地存储中并向用户显示,要求他们打印并保留备份。
  2. 密码被提供给 Thinbus SRP 客户端 JS 库代码,该代码输出客户端盐和密码验证器。
  3. 盐和验证器被发布到服务器并保存在该客户端的数据库中。通常,Thinbus 建议您通过使用 HTTPS 将验证程序发送到服务器来隐藏验证程序,以防止暴力攻击恢复密码。如果您使用随机生成的密码与典型的软件许可证密钥一样长,那么您可以通过 HTTP 传输验证程序。参见下面的脚注 2。

API 使用流程将从客户端的 SRP 身份验证开始,该身份验证具有生成会话密钥的副作用​​。请注意,所有这些都在 Thinbus 演示代码中作为“标准用法”,但在此处进行解释是为了让您了解 STP 身份验证的工作原理。该身份验证协议如Thinbus 页面的序列图所示,并在在线演示中运行:

  1. 客户端 JavaScript 从浏览器本地存储加载 API 密码。
  2. 客户端 AJAX 从服务器获取客户端 salt 和服务器随机一次性数B
  3. 客户端 JavaScript 生成一个一次性数字A,然后使用密码、盐和两个一次性数字生成会话密钥K,并使用两个一次性数字对其进行哈希处理,以创建密码证明,并将M其连同其密码一起发布到服务器随机的A
  4. 服务器使用注册时保存到数据库的密码验证器、客户端盐和两个随机数来计算会话密钥,K然后确认客户端发送的密码证明M是好的。如果一切顺利,它将自己的证明发送M2回客户端。至此,客户端已经使用STP作为密码的零知识证明进行了身份验证。
  5. 客户端检查M2其计算。如果一切顺利,双方都有一个共享秘密,K该秘密是从随机派生的一次性 256 位会话密钥A,并且B中间人无法知道该密钥。
  6. 所有 API 请求和响应都可以使用共享密钥进行 HMAC 签名,并在另一端进行验证。

Thinbus 的 PHP 演示涵盖了上述所有内容,但$srp->getSessionKey()最后实际上调用了一个可用于使用 HMAC 进行签名的密钥。

鉴于 SRP 用加密的零知识密码证明取代了密码身份验证,令人惊讶的是并非所有开发人员都默认使用它。事实上,它还生成用于 API 签名的共享会话密钥,这只是一个额外的好处。


脚注 1:大多数 API 更愿意发布一个包含所有数据的 JSON 值。这是因为 JSON 很简单,但功能更强大,具有 PHP 和 JavaScript 中的内置 API,可以将对象转换为字符串,然后再转换回来。正如 @dbrumann 在评论中指出的那样,有一个用于签名 JSON 的标准,即 JWT。Google 建议使用 PHP 和 JavaScript 来实现此目的。因此,如果您升级为为 API 中的每个命令传递一个 JSON 输入值并返回一个 JSON 输出,您可以使用 JWT 库来签名和验证 API 的 JSON 输入和输出。JWS 算法之一是“JWSAlgorithm.HS256 - 采用 SHA-256、256+ 位秘密的 HMAC”。这些库将整理实际签名和验证的机制,因此您不必编写代码并担心可能的安全错误。

脚注 2: Thinbus 的建议是通过 HTTPS 将密码验证程序传输到服务器,以保证验证程序的机密性。这是为了防止拦截,然后对密码验证器进行离线字典攻击以恢复密码(即密码被加盐到验证器中,因此您需要通过验证器生成代码与用户盐运行16G 破解站密码字典来查找匹配)。通过 API 使用,浏览器window.crypto API 可以生成真正随机的“API 密钥”。通常,Windows 键是向用户显示的 16 个大写字母,格式为 XXXX-XXXX-XXXX-XXXX。检查GRC 密码搜索空间页面后发现,如此大小的随机 16 个字母大写密码需要政府花费 14 年时间才能彻底搜索到。鉴于此估计,您可以安全地通过纯 HTTP 传输为如此长的随机密码生成的密码验证器,而无需加密,因为没有人会切实地投入多年的计算能力来通过验证器生成算法(使用随机数)来运行如此多的密码猜测。客户端盐(因此无法预先计算)来查找匹配项以恢复客户端 API 密码。