将密钥作为 hash_hmac() PHP 函数的数据字符串的一部分包含在内是否安全?

Is is safe to include the key as part of the data string of a hash_hmac() PHP function?

我需要生成一个身份验证令牌以包含在 HTTP GET 请求中以将远程主机作为目标,我在身份验证方面的选项非常有限。

我需要用户登陆自动验证的页面。 He/she 必须执行非常具体的操作,而不是使用整个站点。

我的想法是按以下方式使用 PHP 的 hash_hmac() 函数:

hash_hmac("sha512", $email . $glue . $secret_token . $glue . $_REQUEST["mt"], $secret_token);

因为我的系统与远程主机共享的字段很少:它们是 $email 和 $secret_token.

将 $secret_token 放入数据字符串中会适得其反或危险吗?

因此,HMAC 使用几条信息。你有一个共享的秘密,我假设在你的例子中 $secret_token,它必须保持秘密并且消息有效负载是 public。通常有一个时间戳包含在消息中以及附加到用于过期目的的散列中。例如:$epoch_time . "." . hash_hmac("sha512", $epoch_time . $message, $secret_token); 想法是可以根据 Unix 时间戳检查消息是否超过交付 window。

Can it be counterproductive or dangerous to throw in the $secret_token into the data string?

简而言之,是的。这不是明确的危险,但是没有必要向消息中添加一堆用户提供的(或秘密的)熵,因为 hmac 旨在保留此消息 public。 hmac 背后的想法是验证消息是否正确; IE。授权,未被篡改和可选的特定年龄。

系统之间的身份验证示例:

POST /api/1.0/resource/action HTTP/1.1
HOST: api.local
Content-Type: application/json
Authorization: hmac 1574268077.b8e7ae12510bdfb1812e463a7f086122cf37e4f7

{
  "some": "payload"
}

在接收服务器上,您将检查授权 header。第一部分 (1574268077) 告诉您消息 应该 多长时间(以秒为单位)。第二部分(b8e7ae12510bdfb1812e463a7f086122cf37e4f7)是有效负载和时间戳的哈希值。在这种情况下,您将使用 $epoch_time . '{"some":"payload"}'$message 值来验证请求。查看时间很简单,if (time() - $epoch_time > 5 * 60) { throw new Exception("Message expired") }。我们检查时间戳的原因是为了避免 would-be 攻击者重播消息。 window 越小,越难被滥用。我个人会在某个列表中保留一个 运行 已用但尚未过期的令牌列表,直到它们过期以额外确保它们不能被使用两次。 Redis 或 Memcached 都是存储此类列表的不错选择,因为缓存可以为您处理过期时间。关于 GET/HEAD 和其他不接受请求的端点 body 的快速说明。这些请求的消息可能是包含查询参数的相对 uri。