【问题标题】:Securing a HTTP API保护 HTTP API
【发布时间】:2018-03-16 20:11:54
【问题描述】:

我需要保护一个面向公众的 HTTP API我无法在 API 服务器上接触代码

HTTP API 有多个最终用户,他们将使用非交互式客户端(通常是后端服务)来使用它。需要明确的是,客户端拥有它将访问的资源,因此必须提供给用户,因为授权逻辑需要与最终用户绑定。

我正在考虑使用OAuth2Resource Owner Password Credentials Grant 然后使用提供的访问令牌获取JWT,客户端可以将其呈现给 HTTP 代理,该代理在将请求传递给 HTTP API 服务器之前对其进行解析。

这是我设想的流程:

 +----------+                                  +---------------+
 |          |>--(A)---- Resource Owner ------->|               |
 |          |         Password Credentials     | Authorization |
 | Client   |                                  |     Server    |
 |          |<--(B)---- Access Token ---------<|               |
 |          |    (w/Refresh Token)             |---------------|
 |          |                                  |               |
 |          |>—-(C)---- Request JWT ——-------->| JWT Service   |
 |          |         (w/Access Token)         |               |
 |          |                                  |               |
 |          |<--(D)---- JWT ------------------<|               |
 |          |                                  |               |
 +----------+                                  +---------------+
       v
       |
       |
       |                                       +---------------+
       |                                       |               |
       |                                       |     HTTP      |
       --(E)---- HTTP Request w/JWT ---------->|     Proxy     |
                                               |               |
                                               |      (F)      | 
                                               |               |
                                               +---------------+
                                                       v
                                                       |
                                                      (G)
                                                       |
                                                       v 
                                               +---------------+
                                               |               |
                                               |     HTTP      |
                                               |      API      |
                                               |               |
                                               +---------------+
 
 (A), (B), (C) Get an access token using the Password Grant flow.
 (D) Use access token to get a JWT.
 (E) Attach JWT to HTTP request and send it to the HTTP Proxy.
 (F) Check that JWT is valid.
 (G) Pass request to the HTTP API Server.    
 

有没有其他人解决过类似的用例并愿意提供一些启示或进行讨论?

【问题讨论】:

  • 您是否接受了使用 Oauth 的想法?如果您要进行大型分布式设置,Oauth 非常棒,但是对于“安全的 this 1 api”,任何类型的基于标头的身份验证都可以实现,并且实现起来超级简单
  • 我目前还没有承诺任何事情,但我确实喜欢可以撤销的短期访问令牌的想法,而且我似乎使用 Oauth2 开箱即用。
  • JWT 服务应该做什么?为什么要将自定义 JWT 发送到 API 而不是访问令牌?
  • >oauth 2 “开箱即用”没有什么“开箱即用”,因为符合规范的 OAuth 2 服务器将支持特定声明的访问和刷新令牌。我宁愿不要自己推出这种功能并被超级黑客攻击。 :)
  • @JánHalaša JWT 将用于传递与授权相关的信息,HTTP 前端将解析这些信息以确定用户是否具有访问权限。我想我可以使用 Oauth 2 Scopes 和原始 Oauth 2 访问令牌来完成相同的操作。

标签: oauth-2.0 jwt


【解决方案1】:

我对这个答案投了反对票,所以我最好解释一下自己。

我不是建议“只编写自己的安全库”的人,但我确实对 oauth+api 客户端(尤其是 oauth2)例外。

为什么不用 Oauth2?

  1. 与传统身份验证方案相比,额外的跃点和额外的系统组件,
  2. 很有可能无论你做什么,使用其他编程语言的人可能没有与你正在使用的任何东西兼容的客户端库,people make money making oauth interoperable and simple
    • 想一想:没有人赚钱,即基本身份验证“简单,兼容 1000 多个提供商并且正常工作”(引用 oauth.io),这是因为基本身份验证只适用于每个“ provider”,而 oauth2 有点糟糕、复杂、不可互操作的框架——这就是为什么我们称基本身份验证为“协议”的一部分,我们称 oauth(1) 为协议,但我们将 oauth2 称为 框架
  3. 想想维护非交互式客户端的含义:
    1. 您在整个集群中只有一个不记名令牌,
    2. 因此您将需要一个分布式键值对存储或数据库表来保存它
    3. 您需要捕获特定错误,这意味着承载有 过期了,
    4. 在这种情况下,您需要无缝地请求 再次承载并重试请求(不会丢失请求)。
    5. 这里的问题是,在繁忙的站点上,这可能会在 在 100 个线程上并行
    6. 因此,您需要一个分布式锁定机制来正确执行此操作 - Redis 互斥锁是我在以下情况下的首选毒药 有人用 oauth api 向我打招呼
    7. 那个 + 祝你测试那个复杂的部分好运 分布式竞争条件逻辑,以及当你打破你的背去做 它(嗨 webmock)然后你仍然不时遇到随机的非确定性故障,因为并发之神遇到了 VCR/webmock 不能很好处理的一些条件组合
  4. 这个,或者只是 SHA512 一个秘密以及一个 nonce 和 HTTP 正文

According to the lead author of the Oauth2 project:(我的重点)

所有在邮件列表、会议中、在 特别设计委员会,并在后台渠道导致 规范未能实现其两个主要目标 — 安全和 互操作性。事实上,妥协之一是重命名它 从一个协议到一个框架,另一个添加免责声明 警告该规范不像产生可互操作的 实现。

与 OAuth 1.0 相比,2.0 规范更加复杂, 互操作性较差、有用性较差、不完整且大多数 重要的是,不太安全。

需要明确的是,OAuth 2.0 掌握在具有深度的开发人员手中 对网络安全的理解可能会导致安全 执行。然而,在大多数开发者手中 —  近两年的经验 — 2.0 可能会产生 不安全的实现。

...

在现实世界中,Facebook 仍然在一年后的第 12 轮草案中运行 半年前,完全没有理由更新他们的 执行。毕竟,一个更新的 2.0 客户端可以使用 Facebook 的实施不太可能与其他任何人一起使用 提供者,反之亦然。 OAuth 2.0 几乎没有提供任何代码 可重用性。

2.0 提供的是授权协议的蓝图。作为 定义,它在很大程度上是无用的,必须将配置文件放入工作 解决方案 —— 这就是企业之道。 WS-* 方式。 2.0提供 销售咨询服务和集成的全新前沿 解决方案。

该怎么做?

除非您要创建更大的生态系统,否则 Oauth 通常是矫枉过正。

更简单的解决方案是 DIY,将a custom authorization header 定义为:

authentication_id api_client_id nonce digest

FooApp-SHA512-fixed 4iuz43i43uz chc42n8chn823 fshi4z73h438f4h34h348h3f4834h7384

地点:

  1. authentication_id 是一个固定字符串,描述了正在使用的认证类型,
  2. api_client_id 是标识 API 客户端的公共信息(我假设 API 有超过 1 个客户端,或者在某个时候它将有超过 1 个客户端) - API 客户端 ID 允许您匹配 API客户端与 API 客户端的secret
  3. nonce 只是一个随机字符串
  4. secret 是一个只有您和客户端知道的随机字符串,客户端应将其视为密码(即不要将其提交给版本控制)
  5. digestapi_client_id + nonce + secret 的 SHA512 hex/base64 摘要(您也可以添加连接 HTTP 正文,除非正文很大,否则我会添加 HTTP 正文 - 例如使用文件上传)

如果客户端通过身份验证,只需将请求转发到后端 API 服务并将其响应返回给客户端,否则会呈现错误。

【讨论】:

  • 我不明白为什么有人会编写自己的自定义协议/格式代码并推出自己的加密货币,而有标准组件来处理 OAuth 2.0。参见例如github.com/pingidentity/mod_auth_openidc 用于代理组件。
  • 上面还提供了 MAC,它易于理解和推理,需要更少的跳数和系统组件来维护,学习曲线更简单,因为保护 API 不是火箭科学,我们一直在做很长一段时间以来,“我们”中的大多数人现在都知道如何在没有 oauth2 的情况下做到这一点。比较设置和集成 oauth2 服务与仅做“编写 API 时通常做的事情”之间的工作时间
  • 在安全方面,你可能更有可能通过摆弄一个你没有经验的 oauth2 服务提供商而不是像往常一样编写一个 api 身份验证器。祝你好运,然后设置 mac 检查这是否适合你。
  • @HansZ。我扩展了我的答案,包括“为什么一个人会编写自己的自定义协议/格式代码并推出自己的加密货币,而有标准组件来处理 OAuth 2.0”
【解决方案2】:

OAuth2 有很多优点...

它有一个清晰的流程和多种类型的资助,可以用来满足不同的需求。

另一个优点是有一些库可以处理 OAuth2 的复杂性,例如 Identity Server:https://identityserver.github.io/Documentation/

无论这对您的项目是否矫枉过正,只有您才能回答这个问题。许多声称 OAuth2 很复杂的人并没有真正花足够的时间来理解它。

我建议您不要依赖任何类型的自建安全模型,因为这是导致系统崩溃的原因。 OAuth2 库已经过大量用户和公司的实战测试。

很多提供 api 的公司都是通过 OAuth2 实现的。

因此,归根结底,如果您确实想使用它,请进行研究,了解它然后实施它。

至于您的实际问题,是的,我已经构建了具有大量用户的类似系统,使用了各种赠款,一切都运行良好。只要您花足够的时间了解自己的所作所为,就没有什么好害怕的……

【讨论】:

  • 我同意,研究是件好事。这个线程有帮助。现在,我并没有点击如何专门针对这个特定用例使用 OAuth 2。我需要支持非交互式客户端。这让我只能使用Resource Owner Password Credentials Grant。这对于可以保密的后端服务来说很好,但如果我想扩展它以支持基于用户代理的客户端怎么办?
  • 另外,想想维护非交互式客户端的含义。您在整个集群中只有一个不记名令牌,因此您需要一个键值存储或一个数据库表来保存它。您将需要捕获表示承载已过期的特定错误,在这种情况下,您将希望再次无缝地请求承载而不会丢失请求。这里的问题是,在繁忙的站点上,这可能会在 100 多个线程上并行发生。所以,你需要一个分布式锁定机制来做正确的事——redis 互斥锁是我的首选。那个,或者只是 SHA512 一个秘密 + nonce + http body
猜你喜欢
  • 2016-08-22
  • 2013-12-17
  • 1970-01-01
  • 2014-01-16
  • 2019-12-27
  • 1970-01-01
  • 2014-08-27
  • 2018-04-28
  • 2019-06-03
相关资源
最近更新 更多