安全 - 如何保护 HTTP GET 请求中的 api 密钥

security - how to secure api key in HTTP GET request

我是密码学的新手,我正在尝试防止我正在开发的 Web 服务中的中间人攻击。 Web 服务的工作方式是用户使用他的电子邮件地址和密码在服务上注册并创建应用程序。每个应用程序都有一个应用程序 ID 和一个应用程序密钥。应用程序 ID 是 public(这就是 public 与该应用程序通信的方式)但应用程序密钥是私有的。用户通过加载一个 pin(一个 16 位数字字符串)来记入他的应用程序。加载 pin 是通过 HTTP Get 请求完成的。

现在我的问题是:用户如何使用他的应用程序 ID(服务器识别应用程序的方式)和他的应用程序密钥(服务器验证他的方式)执行 HTTP GET 请求而不泄露他的应用程序密钥?

因为我们的服务器有 SSL(而且我读到 SSL 可以防止中间人攻击),我正在考虑简单地让用户提交他们的应用程序 ID 和应用程序密钥作为 GET 请求中的参数,但在阅读之后,我认为这可能不安全。这也是因为在执行 HTTP GET 请求以加载 pin 后,用户可以配置他的帐户,我们通过另一个 HTTP GET 请求将服务器响应提交到他选择的 URL。由于我们想回显他的应用程序 ID 和应用程序密钥,以便他可以验证请求确实来自我们,我担心他的密钥可能会被泄露。

所以我决定我们应该让用户对其应用程序 ID 和应用程序密钥进行 md5 散列以提供散列参数并在 GET 请求中提交该参数而不是他的应用程序密钥。然后在我们的服务器上,因为我们已经知道用户的应用程序 ID 和应用程序密钥,我们可以简单地对两者进行 md5 哈希并将其与用户提交的哈希参数进行比较。但后来我也认为这可能是不安全的,因为如果有人截获哈希参数,攻击者可以使用相同的哈希参数提交多个请求,因为应用程序 ID 和应用程序密钥是静态的。所以在long运行中,hash参数和app key没有区别

现在我在想,我们应该让用户对他的应用程序 ID、他的应用程序密钥和他想要加载的 pin 进行 md5 哈希以获得哈希参数。这样,由于每次 pin 总是不同的,即使攻击者拦截了一个请求,身份验证过程也不会因其他请求而受到损害,因为攻击者将无法将该哈希值与其他请求一起使用。

例如,如果用户具有以下凭据: 1. app_id: 1234 2. app_key: bghuTHY678KIjs78

并且用户想要加载密码:1234567890123456

他通过对“1234:bghuTHY678KIjs78:1234567890123456”进行 md5 哈希来生成哈希。这给了他 210a4c92d85473af9d5f48b4ee182ddd。然后他向以下地址发出 HTTP Get 请求:

https://example.com/process?app_id=1234&pin=123456789012&hash=210a4c92d85473af9d5f48b4ee182ddd

这种方法安全吗?或者我应该只是让用户在 HTTP GET 请求中提交他们的应用程序 ID 和应用程序密钥,因为我们有 SSL?

绝不能通过网络发送用户机密。相反,请用户使用他的秘密签署他的请求。 HMAC 是相关算法。

顺便说一句,MD5 已过时且不安全,无法满足所有加密需求。

使用Secure Remote Password (SRP6a) and register a password verifier and salt for the 16 digit pin. The pin you never send to the server (you can store it in browser local storage for convenience of the user). Then authenticate the client using SRP6a which results in a strong shared secret session key for each successful authentication. Then use HMAC SHA256 to sign API calls using the session key. See the thinbus-srp JavaScript library and its demos of using SRP6a to authenticate resulting in a session key. See the JWS "HS256"(HMAC with SHA-256, 256+ bit secret)算法和任何实现该算法的库作为使用共享安全密钥签署网络的示例API。

SRP6a 身份验证协议是一种安全的零知识密码证明,服务器不知道密码。服务器向客户端发出随机挑战,客户端根据挑战生成密码证明。服务器使用客户端为其密码提供的验证器来检查密码证明。如果 16 位 pin 使用大写字母,如标准软件许可证密钥,则 运行 对验证者进行字典攻击是不可行的。使用现代浏览器 webcrypto 安全随机数生成器在浏览器中生成密码。连你也拿不到密码

使用 SRP6a 进行身份验证的开销是您需要客户端首先获取服务器质询。您的用例的好处是,如果客户端根据挑战提供良好的密码证明,则客户端和服务器共享安全会话密钥。没有人拦截流量可以知道会话密钥。使用该共享密钥,您可以对每个 API 调用进行签名和验证,并在服务器上验证签名。没有人拦截您和客户之间从注册到使用的端到端任何交换的任何部分,从而获得任何优势。