对 HTTP 请求进行身份验证和签名

Posted

技术标签:

【中文标题】对 HTTP 请求进行身份验证和签名【英文标题】:Authenticate and sign HTTP request 【发布时间】:2016-04-28 13:21:06 【问题描述】:

我正在寻找有关(完整性检查)的最佳做法的一些指导/意见。对于所使用的语言和技术,我对此相当开放,但基本参数和要求如下:

需要身份验证和完整性检查。 该请求包含敏感数据并将通过 HTTPS 传递,但我不能假设该请求不能被攻击者嗅探,无论是在它被 HTTPS 加密之前(在客户端由一些非法安装的软件)还是在服务器端,例如通过放置在 HTTPS 端点和实际服务器之间的嗅探器。 HTTPS 加密/解密处理已被传递给外部负载平衡器,因此攻击者可以在一个小窗口中在负载平衡器和服务器之间插入嗅探器。 我需要确保交易不会被伪造。 我需要确保无法重播事务。 请求可以是 GET 或 POST,因此任何额外的数据都需要保持在 GET 请求的最大大小限制内。

我们考虑过的事情:

每个请求的用户名/密码。我猜这保证了身份验证,但如果攻击者可以嗅探用户名/密码对,那么一切都会失败。 每个请求的私钥签名。服务器将拥有公钥,只有客户端拥有私钥。这保证了完整性,因为只有客户端可以生成签名,但服务器可以检查签名。它通常也保证身份验证,因为私钥不是请求数据的一部分并且无法被嗅探。但是,它本身并不会停止重放交易,因为具有相同数据的 2 个交易将具有相同的签名。 使用加密客户端随机数 (https://en.wikipedia.org/wiki/Cryptographic_nonce) 作为请求数据的一部分并将其包含在要签名的数据中。我们遇到了这些问题,特别是当它们在客户端生成时,因为如果它们不够随机,那么攻击者可以找出它们是如何生成的,然后攻击者可以在生成之前生成自己的随机数序列客户端生成相同的序列,这可能导致拒绝服务攻击,因为客户端将尝试重新使用攻击者已经使用的随机数。已考虑在服务器端生成随机数,但这是一项额外的事务,并且可能存在性能问题。 在请求数据中包含日期/时间,但这可能会导致客户端时钟和服务器时钟不同步的问题。

如果某些管理员决定将此标记为重复,以下是我认为并不能完全解决此问题的全部范围的其他问题:

What is the current standard for authenticating Http requests (REST, Xml over Http)? Authenticity and Integrity of HTTP Requests

【问题讨论】:

“我对所使用的语言和技术持开放态度” - 那你为什么要在 Stack Overflow 上提问?这不再是一个真正的编程问题,如果是,那么它就太宽泛了。 Information Security 更适合这类问题。 【参考方案1】:

假设客户端和服务器之间是 1-1 的关系,带有计数器的 HMAC 将解决这个问题。

客户端和服务器有一个共享的 128 位密钥。

客户端发送具有带有密钥的 HMAC 和计数器的消息。推荐使用 SHA-256,因为 SHA-1 即将淘汰(虽然 SHA-1 HMAC 仍然被认为是安全的,但那是另一回事了)。

例如

example.com?message=foo&counter=1&hmac=35ed8c76e7b931b06f00143b70307e90f0831682e7bdce2074ebb5c509d16cfb`

(This tool 用于此帖子,秘密为bar。)

HMAC 是通过 message=foo&counter=1 计算得出的。

现在,一旦服务器对 HMAC 进行了身份验证并检查了计数器,服务器的计数器就会增加到 2。现在服务器将不接受任何计数器小于 2 的经过身份验证的消息。

JSON Web Tokens 可以用于以标准格式执行上述操作。您可以对多个客户端执行上述操作,但是您需要跟踪每个客户端的计数器服务器端,并且客户端必须在消息中标识自己。如果您决定为每个客户端使用不同的密钥,那么管理共享密钥是最棘手的问题。

【讨论】:

感谢 JWT 的指针,我认为有一些标准格式可以做到这一点,但到目前为止我还没有发现。我们在客户端和服务器之间有一个多:1 的关系,但是我们没有太多的客户端,以至于我们无法为每个客户端维护不同的密钥(我们有大约 15 个客户端)。在此期间,我们决定使用 RSA 密钥而不是 HMAC 来实现一些东西,但我看到 JWT 也支持这一点。 我不喜欢 JWT 的一点——不透明的、base64 编码的有效负载会使调试变得不那么友好。

以上是关于对 HTTP 请求进行身份验证和签名的主要内容,如果未能解决你的问题,请参考以下文章

Azure 服务器未能对请求进行身份验证。确保授权标头的值格式正确,包括签名

AWS 身份验证和日志记录

使用 Xamarin Forms 使用自签名证书对 Azure AD 进行身份验证

如何在 PHP 中生成 QuickBlox 身份验证签名?

reSolve 框架:如何通过 HTTP 请求(路由 RegisterCallback)对用户进行身份验证?

Ruby 使用标头进行身份验证的方法?