我为一个项目创建了一个简单的 RESTful API,部分遵循Riyad Kalla 的这篇非常好的博客文章。现在,我在 Stack Overflow 上阅读了几十个类似的问题,但我似乎无法找到我的安全问题的答案。
简而言之,我的请求是这样的:
- 客户端有一个公共 API 密钥(纯文本,任何嗅探网络流量或正确检查代码源的人都可以访问)
- 客户端使用公共 API 密钥向服务器发送请求
- 服务器有一个秘密的 API 密钥(对除开发人员以外的任何人都是秘密的)
- 服务器创建一个由客户端请求数据和秘密 API 密钥组成的 HMAC-SHA1 哈希
- 服务器向 API 服务器发送与客户端请求相同的请求,但包括生成的 HMAC-SHA1
- API 服务器根据它收到的公共 API 密钥在其数据库中查找秘密 API 密钥
- API 服务器使用与开发者服务器相同的数据重新创建 HMAC-SHA1 哈希
- 如果哈希匹配,则认为请求有效并正常处理
我担心使用我的服务的人可以获取公共 API 密钥(比如说通过嗅探网络流量),然后简单地将客户端最初使用 AJAX 通过浏览器执行的相同请求直接卷曲到开发人员的服务器。因此,恶意用户可以被认证为合法用户,并使用其他人的秘密 API 密钥访问 API。
我将尝试举一个具体的例子。通常我会这样做:
- AJAX 对我的服务器的获取请求。
- 我的服务器使用我的 API 密钥对我的请求进行哈希处理并将其发送到 API 服务器。
- API 服务器验证我的请求并返回有效负载。
但我很害怕:
- Dr. Evil 会嗅探我的公共 API 密钥。
- Dr. Evil 将使用我的公共 API 密钥将 get 请求卷曲到我的服务器。
- 我的服务器将使用我的 API 机密对 Dr. Evil 的请求进行哈希处理,并将其发送到 API 服务器。
- API 服务器验证并返回有效载荷以完成 Dr. Evil 的恶毒计划。
- 邪恶博士发出邪恶的笑声。
我遗漏了什么,或者这只是 RESTful API 游戏的一部分?
更新:我自愿省略任何形式的时间戳验证,以保持简单,只关注身份验证问题。
更新 2:我$_SERVER['HTTP_REFERER']
在流程中添加了验证。这里的目标是客户端必须与请求一起发送引荐来源网址,并且它必须与 API 端数据库中列出的引荐来源网址相匹配。不幸的是,HTTP 引荐来源网址很容易被伪造。这是另一个级别的安全性,但仍不完美。
更新 3:我已更改服务器端代码以将引用者设置为远程 IP 地址。这会强制发送到我的服务器的每个请求都希望使用秘密 API 密钥进行哈希处理,最终到达具有原始请求 IP 地址的 API 服务器。然后可以验证此 IP,并且可以通过请求。我相信仍然可以伪造$_SERVER['REMOTE_ADDR']
,但它比伪造更复杂$_SERVER['HTTP_REFERER']
......我猜仍然不完美。
更新 4:根据这些帖子:如何伪造 $_SERVER['REMOTE_ADDR'] 变量?和https://serverfault.com/questions/90725/are-ip-addresses-trivial-to-forge$_SERVER['REMOTE_ADDR']
,虽然很困难,但伪造是可能的。但是,由于您无法控制伪造的网络,因此不可能收到来自伪造请求的响应。请求可以成功验证,但其响应不会落入恶意之手。