REST API 设计:GET 需要不应存储在 Web 服务器日志中的敏感参数

Posted

技术标签:

【中文标题】REST API 设计:GET 需要不应存储在 Web 服务器日志中的敏感参数【英文标题】:REST API Design: GET requires sensitive parameters that should not be stored in web server logs 【发布时间】:2015-11-19 16:34:00 【问题描述】:

我正在设计一个(尽可能使用 RESTful)API,想知道您将如何最好地解决以下问题:

假设我们正在设计一个 TLS 端点来检索一些资源:GET /objects/id 我们不希望对象ids 存储在我们的Web 服务器日志中,因此我们希望避免使用查询字符串或URI 参数;这给我们留下了请求正文中的参数。 (假设数据是这样的 id 是敏感的,我们无权访问另一个非敏感 id) 我了解建议不要在 GET 请求正文中包含参数。 HTTP GET with request body 我了解也不建议使用 POST 获取数据,因为它更倾向于 RPC 设计风格,并且通常可能会造成混淆。

我们如何(应该)设计 API GET 端点以避免使用可以记录的查询或 URI 参数? 在这种情况下使用 POST 是否可以接受,还是有其他创造性的方式? (注意:此 API 不会暴露给第三方)

【问题讨论】:

【参考方案1】:

我认为有很多服务都面临着想要保护敏感标识符的问题。然而,即使这个问题已经有好几年了,我也没有找到合适的解决方案。

所提供的简单地更改网络服务器日志记录的解决方案并不完美,如前所述,但也忽略了这样一个事实,即每个客户端在使用您的 API 时都应该做同样的事情(其中可能是 javascript 客户端,通过代理,在浏览器中...祝你好运)

我知道的解决方案是:

    加密参数;但这会使您的 API 更加复杂,并且需要加密密钥。

    使用@jj-geewax 提到的伪 ID;然而,这可能比加密 (1) 更复杂,因为您必须为每个敏感参数实例交换一个伪 ID:

    客户端在其对服务器的请求中使用伪 ID 发起,服务器向客户端发出请求以解析伪 ID! (所以客户端也应该有一个端点!) 客户端将敏感 ID 发布到服务器,它会收到一个伪 ID,它可以在对该 ID 的请求中使用它 客户端和服务器提前通过其他方式交换了伪 ID

    POST body 中的参数,同时请求数据;这不是 REST

    可以选择使用 X-HTTP-Method-Override 使您实际请求数据的应用程序更加明确。

解决方案 3 似乎是迄今为止最简单/最容易实现的方法,尽管它违反了 REST 设计规则。但我很想听听其他方法或其他见解。

更新:OWASP 关于请求中的敏感参数说明如下

HTTP 请求中的敏感信息

RESTful Web 服务应小心防止泄露凭据。密码、安全令牌和 API 密钥不应出现在 URL 中,因为这可以在 Web 服务器日志中捕获,这使得它们具有内在价值。

在 POST/PUT 请求中,敏感数据应在请求正文或请求标头中传输。 在 GET 请求中,敏感数据应在 HTTP 标头中传输。

https://cheatsheetseries.owasp.org/cheatsheets/REST_Security_Cheat_Sheet.html#sensitive-information-in-http-requests

这可能比使用 (POST) 主体更难,但在研究如何实现 REST 时也很好。

【讨论】:

显然 OWASP 也写过这方面的文章并提供了一个额外的解决方案:在 GET cheatsheetseries.owasp.org/cheatsheets/… 中使用标头 @LvanderRae 感谢回复和研究。对于其他审查此内容的人,在我发布此内容后的这些年里,我带走的一件事就是做对你有用的事情。我采取的解决方案是使用 POST。这不是理想的、直观的,也不是 RESTful 的,但最终没关系,因为我们从来没有要求纯粹是 RESTful。重要的是我们没有冒险在 URL 中暴露敏感数据。 对于考虑使用 X-HTTP-Method-Override(或类似)标头的用户,请注意您可能通过允许攻击者发送 GET 或 POST 但使用如果您不小心,标头会导致您的后端解释为 DELETE。 vulncat.fortify.com/en/…【参考方案2】:

如果您使用 Apache 作为您的网络服务器,您可以使用 CustomLog 删除/替换敏感值,this answer 提供了一个示例脚本。

【讨论】:

是的,你是对的,但是,我现在需要更具体一些。我想从 API 设计的角度来解决这个问题,而不是依赖运营团队来记住不要使用会记录敏感值的 CustomLog 值。 这对于解决您的日志很好,但它并不能减轻通过浏览器历史记录或书签的披露。抓取这些数据通常是由恶意浏览器扩展程序和插件完成的。【参考方案3】:

一般来说,如果您坚持使用 REST,则应将标识符保留在 URL 路径中(例如,/objects/id)并坚持使用GET HTTP 方法,但我可以理解您遇到的问题和。如果这个 ID 在某种程度上是秘密的,那么关闭这个神奇的秘密 ID 的日志记录绝对是个好主意。也就是说,您遇到的问题可能表明您的 API 存在更大的设计问题,并且阻止日志记录可能无法解决更大的问题。

例如,这是否是“默默无闻的安全性”(例如,ID 是一个秘密,任何知道它的人都可以访问数据)?或者只是保护敏感信息(例如,像美国社会安全号码的 ID 这样的 PII)?在上述任何一种情况下,使用此值作为标识符都可能是个坏主意。

如果这个 ID 本身是敏感的,那么可能值得为每个资源生成一个随机标识符,然后开始传递它。如aip.dev/2510 中所述,Google Cloud 使用项目(ID 与编号)来执行此操作。请注意他们如何明确声明第三方无法使用项目 ID,并且将始终以不透明的项目“编号”作为标识符进行操作。

如果这是隐蔽的安全性,那么您可能需要某种身份验证/授权令牌或 GET 请求中的标头,从 RESTful 的角度来看,这应该没问题。这意味着某人可以获取秘密标识符,因为如果没有其他一些凭据集,它就毫无用处。

我当然会告诫不要将您的 HTTP 方法切换为 POST 只是为了避免记录敏感内容。从长远来看,这会给从事该项目的新员工带来困惑,并阻止您使用任何对 API 做出 RESTful 假设的工具。

【讨论】:

以上是关于REST API 设计:GET 需要不应存储在 Web 服务器日志中的敏感参数的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript AJAX 调用中的安全 REST API 令牌

向 Azure Blob 存储发出 GET 请求时授权失败 [REST API][Azure Blob 存储]

Django REST framework框架之GET, POST, PUT, PATCH, DELETE等API请求接口设计

使用需要不记名令牌的 API 在 Python 中进行 API 调用

使用 Postman 获取 aws 存储桶内容列表 - “Get Bucket (Version 2)”Rest API

REST API 的认证和授权设计