在请求的 URL 中包含 API 密钥是否安全?

信息安全 tls http 网址
2021-08-26 01:07:42

最近我看到很多这样设计的 API:

curl "https://api.somewebsite.com/v1/something&key=YOUR-API-KEY"

至少在 HTTP 中,将查询字符串中的 API 密钥作为 URL 的一部分传递是不安全的,这不是很简单吗?

4个回答

这通常称为能力 URL /秘密 URL。

它在现代网站中是安全的,但并不适用于所有应用程序,并且需要非常小心地使用.

您可以在W3C 的此页面中找到对它们的优势、风险和最佳实践的出色概述


不指定威胁模型就谈安全是没有意义的。以下是我想到的一对:

  • 1:网络上的被动攻击者(窃听)
  • 2:网络上的主动攻击者(可以随意更改数据包,mitm等)
  • 3:肩部冲浪者
  • 4:可以物理访问您的计算机/提升权限的攻击者
  • 5:您计算机的另一个用户(常规权限/远程访问)
  • 6:用户本身(如保护 API 密钥)

关于网络攻击(1 和 2),功能 URL 是完全安全的,前提是您使用的是 HTTPS(现在是 2016 年,您不应该再使用 HTTP!)。

虽然服务器的主机名通过网络以明文形式发送,但实际 URL 在发送到服务器之前会被加密——因为它是 GET 请求的一部分,仅在TLS 握手之后发生。


关于肩膀冲浪(3),具有足够熵的能力 URL 可以安全地抵御偶然攻击,但不能抵御专门的攻击者·

例如,一个谷歌文档 URL:

https://docs.google.com/document/d/5BPuCpxGkVOxkjTG0QrS-JoaImEE-kNAi0Ma9DP1gy

祝你好运,在经过同事的屏幕时记住这一点!

显然,如果你的攻击者有相机,并且可以在不被注意的情况下拍照,那就完全不同了如果您要保护的信息会使您的用户面临此类攻击的风险,那么您可能不应该使用功能 URL。或者至少通过从功能 URL 进行 HTTP 重定向来缓解问题,因此它只会在屏幕上显示几秒钟,


对于在您的计算机上具有提升权限的攻击者 (4),功能 URL 的安全性不亚于长密码甚至客户端 TLS 证书 - 因为所有这些实际上都是完全不安全的,而且您无能为力那。

另一方面,具有常规权限 (5) 的攻击者也不应该能够学习功能 URL,只要您遵循良好的操作系统安全实践即可您的文件(尤其是浏览器历史记录)不应被其他用户读取。

如果您与其他人共享您的计算机帐户,这也是非常不安全的。共享计算机的一个好的经验法则是不要使用它们来访问您不会在街上大声说出来的任何信息。


为了保护 API 密钥(6,这是这个问题的重点),功能 URL 也与不太明显的机制(例如 AJAX POST)一样安全任何使用 API 密钥的人都知道如何使用浏览器调试模式来获取密钥。

向某人发送秘密并期望他们不看它是不合理的!


有人问过服务器端的风险。

在这种情况下,通过威胁建模来处理服务器端风险是没有用的。从用户的角度来看,您确实必须将服务器视为受信任的第三方,就好像您的对手在服务器端具有内部网络访问权限,您实际上无能为力(非常像客户端计算机上的特权攻击者,即上述威胁模型 4)。

我将概述无意泄露秘密的常见风险,而不是对攻击进行建模。

在服务器端使用功能 URL 最常见的问题是HTTP 服务器和反向代理都保留日志,并且 URL 经常包含在内

另一种可能性是,能力 URL 可以以可预测的方式生成- 要么是因为有缺陷的实现、不安全的PRNG ,要么是在播种时提供的熵不足

在设计使用功能 URL 的站点时,还必须考虑许多警告。

在实践中,对于具有动态内容的网站,很难安全地完成所有事情 -谷歌Dropbox过去都把它搞砸了,正如这个答案所提到的


最后,与其他身份验证方法相比,功能 URL 有几个优点

  • 它们非常易于使用(只需单击链接,而不是输入您的电子邮件和密码)
  • 他们不需要服务器/服务安全地存储敏感的用户凭据
  • 与共享密码(您在其他 50 个站点重复使用)不同,它们很容易共享而没有风险。

这取决于该 API 的使用方式以及它正在访问的数据类型。访问谷歌地图的东西(例如)比访问银行数据的东西风险低得多。

显然,在客户端代码中这样的调用是不安全的,用户可以轻松了解您的 API 密钥。

如果 API 调用是服务器到服务器的,那么问题就不大了。

使用 HTTP 会使连接被窃听,HTTPS 消除了这个问题。

URL 中键的另一个问题是完整的 url 最终出现在日志文件中。这扩大了应用程序的攻击面,因为现在有更多的地方可以寻找密钥。

要回答您的问题,并不是在 URL 中传递密钥本质上是不安全的,而是它不如替代方案安全,而不是最佳实践。假设 API 没有访问敏感的东西,连接是通过 HTTPS 并且调用是服务器到服务器的,对于低风险服务来说应该“足够好”。

一般来说,将机密作为 GET 参数传递并不是一个好主意。不久前,我在博客上整理了一份关于潜在安全问题的列表:

秘密可能会泄露给其他方,如下所示:

从您的计算机/智能手机

服务器端

  • 网络服务器日志
  • 日志聚合服务,例如 SIEM、Elasticsearch、Splunk
  • 搜索引擎索引的日志文件(相关Google dork
  • 反向代理日志

致第三方

  • 代理日志(例如在企业环境中)
  • 异常报告服务,例如RollbarSentry
  • Referer通过标题的其他网站
  • 朋友,如果 URL 在电子邮件或 IM 消息中共享
  • 公共云中的其他租户

其中一些不适用于 Ajax 请求,但 ymmv

我想知道为什么没有人明确提到会话固定和 CSRF 漏洞的风险。当然,您可以通过添加 CSRF 令牌并实施安全会话处理来缓解这些问题,但这意味着您实际上可以控制相关代码。

由于这个问题的标题A secret in a URL有些人可能会得出这样的结论,即如果他们实施一些缓解措施而不是将其视为可以避免的可能攻击媒介就足够了。