为什么 2023 年 OAuth 仍然很难?

译文
开发 开发工具
我们为 50 个最流行的 API 实现了 OAuth,例如 Google(Gmail、Calendar、Sheets 等)、HubSpot、Shopify、Salesforce、Stripe、Jira、Slack、Microsoft(Azure、Outlook、OneDrive)、LinkedIn、Facebook 和其他 OAuth API等‍。

51CTO读者成长计划社群招募,咨询小助手(微信号:CTOjishuzhan)

作者 | Robin Guldener

策划 | 言征

OAuth 是一个标准协议。基本上你可以想象的每种编程语言都有 OAuth 2.0 的客户端库。

但有了客户端库,却并不意味着万事大吉,如果你能够在大约 10 分钟内做到为任何 API 实施 OAuth。或者至少在一个小时内,请给我们发电子邮件——我们想请你吃一顿美味的晚餐,并听听你是怎么做到的。

1、50 个 OAuth 实践:结果一团糟

我们为 50 个最流行的 API 实现了 OAuth,例如 Google(Gmail、Calendar、Sheets 等)、HubSpot、Shopify、Salesforce、Stripe、Jira、Slack、Microsoft(Azure、Outlook、OneDrive)、LinkedIn、Facebook 和其他 OAuth API等。

我们的结论:现实世界的 OAuth 体验可与 2008 年的 JavaScript 浏览器 API 相媲美。人们普遍认为应该如何做事,但实际上每个 API 都有自己对标准、实现怪癖以及非标准行为和扩展的解释. 结果:到处都是坑。

2、OAuth 标准太大太复杂

“这个 API 也使用 OAuth 2.0,我们几周前就已经这样做了。我应该在明天之前完成。”

——实习生的著名遗言

OAuth 是一个非常大的标准。OAuth 2.0 的官方网站目前列出了 17 个不同的 RFC(定义标准的文档),它们共同定义了 OAuth 2 的工作方式。它们涵盖了从 OAuth 框架和 Bearer 令牌到威胁模型和私钥 JWT 的所有内容。

“但是,”我听到你说,“肯定不是所有这些 RFC 都与使用 API 的简单第三方访问令牌授权相关吗?”

你说得对。让我们只关注可能与典型的 API 第三方访问用例相关的事情:

OAuth 标准:OAuth 2.0 现在是默认的,但是 OAuth 1.0a 仍然被一些人使用(2.1 即将到来)。一旦你知道你的 API 使用了哪一个,请继续。

授予类型:你需要authorization_code、client_credentials还是device_code?它们的作用是什么,你应该在什么时候使用它们?如有疑问,请尝试authorization_code。

旁注:刷新令牌也是一种授权类型,但有点特殊。它们的工作方式是标准化的,但你最初要求它们的方式却不是。稍后会详细介绍。

现在你已准备好处理你的请求,让我们看看许多(准确地说是 72 个)具有定义的含义和行为的官方 OAuth 参数。常见示例有prompt、scope、audience、resource、assertion和login_hint。然而,根据我们的经验,大多数 API 提供者似乎都没有注意到这个列表,就像你可能直到现在一样,所以不要太担心它。

如果你认为这仍然感觉太复杂并且需要学习很多东西,我们倾向于同意你的看法。

大多数构建公共 API 的团队似乎也同意这一点。他们没有实现完整的 OAuth 2.0 子集,而是只实现了他们认为 API 用例所需的 OAuth 部分。这导致文档中有相当长的页面概述了 OAuth 如何为这个特定的 API 工作。但是我们很难责怪他们;他们的 DX 只考虑最好的意图。如果他们真的试图实施完整的标准,你需要阅读一本小书!

Salesforce authorization_code OAuth 流程。为什么不喜欢这个简单的 10 步过程的清晰视觉效果?

图片

问题在于每个人对于 OAuth 的哪个子集与他们相关的想法略有不同,因此你最终会得到许多不同的(子)实现。

3、每个人的 OAuth 都有细微差别

由于每个 API 都实现了不同的 OAuth 子集,你很快就会陷入被迫详细阅读 OAuth 文档的长页的情况:

他们在授权调用中需要哪些参数?

  • 对于 Jira,audience参数是 key(并且必须设置为特定的固定值)。谷歌更喜欢通过不同的范围来处理这个问题,但真正关心的是提示参数。同时,Microsoft 的某个人发现了response_mode参数并要求你始终将其设置为query。
  • Notion API 采用了一种激进的方法,取消了无处不在的范围参数。事实上,你甚至不会在他们的 API 文档中找到“作用域”这个词。Notion 将它们称为“功能”,你可以在注册应用程序时设置它们。我们花了 30 分钟才明白发生了什么。他们为什么要重新发明这个轮子?
  • 使用offline_access会变得更糟:现在大多数 API 都会在短时间后过期访问令牌。要获得刷新令牌,你需要请求“offline_access”,这需要通过参数、范围或你在注册 OAuth 应用程序时设置的内容来完成。有关详细信息,请咨询你的 API 或 OAuth 医生。

他们希望在令牌请求调用中看到什么?

  • 某些 API,如 Fitbit,坚持在标头中获取数据。大多数人真的希望它在正文中,编码为x-www-url-form-encoded,除了少数,例如 Notion,它更喜欢将它作为 JSON 获取。
  • 有些人希望你使用基本身份验证来验证此请求。许多人对此并不在意。但要小心,他们明天可能会改变主意。

我应该在哪里重定向我的用户进行授权?

  • Shopify 和 Zendesk 有一个模型,在该模型中,每个用户都会获得一个子域,例如 {subdomain}.myshopify.com。是的,它包括 OAuth 授权页面,因此你最好将动态 URL 构建到你的模型和前端代码中。
  • Zoho Books 为不同地点的客户提供不同的数据中心。希望他们记住他们的数据所在的位置:要授权你的应用程序,你的美国客户应该访问 https://accounts.zoho.com,欧洲人可以访问 https://accounts.zoho.eu,欢迎印度人访问 https://账户.zoho.in. 清单还在继续。

但至少我可以选择我的回调 URL,不是吗?

如果你输入http://localhost:3003/callback作为 Slack API 的回调,他们会友善地提醒你“请使用 https 确保安全”。是的,也适用于本地主机。幸运的是,在 localhost 上有 OAuth 重定向的解决方案。

我们可以继续讨论很长时间,但我们认为你现在可能明白了。

图片

  • OAuth 太复杂;让我们制作一个更简单的 OAuth 版本,它拥有我们需要的一切!XKCD

4、许多 API 向 OAuth 添加非标准扩展

尽管 OAuth 标准非常庞大,但许多 API 似乎仍然在其中寻找所需功能的差距。我们看到的一个常见问题是,除了access_token之外,你还需要一些数据才能使用 API。如果这些额外的数据可以与 OAuth 流中的 access_token 一起返回给你,那不是很好吗?

我们实际上认为这是一个好主意——或者至少比强迫用户在之后执行古怪的额外 API 请求来获取此信息(看看你,Jira)要好。但这确实意味着你特别需要为每个 API 实现更多非标准行为。

以下是我们见过的一小部分非标准扩展:

  • Quickbooks 使用realmID,你需要在每个 API 请求中传入它。他们唯一一次告诉你这个realmID是作为 OAuth 回调中的附加参数。最好将它存放在安全的地方!
  • Braintree 对companyID做同样的事情
  • Salesforce 为每个客户使用不同的 API 基本 URL;他们称之为instance_url。值得庆幸的是,他们在令牌响应中返回了用户的instance_url和访问令牌,但你确实需要从那里解析并存储它。
  • 不幸的是,Salesforce 还做了更烦人的事情:访问令牌在预设时间后过期,这可以由用户自定义。到目前为止还不错,但出于某种原因,当你刚收到的访问令牌将过期时,他们不会在令牌响应中告诉你(其他人都会这样做)。相反,你需要查询额外的令牌详细信息端点以获取令牌的(当前)到期日期。为什么,Salesforce,为什么?
  • Slack 有两种不同类型的范围:你作为 Slack 机器人拥有的范围和允许你代表授权你的应用程序的用户采取行动的范围。很聪明,但他们并没有为每个范围添加不同的范围,而是实现了一个单独的user_scopes参数,你需要在授权调用中传递该参数。你最好了解这一点,祝你好运,在你的 OAuth 库中找到对此的支持。

为了简洁起见,我们将跳过我们遇到的许多非真正标准的 OAuth 流程。

5、“invalid_request”调试 OAuth 流程很困难

调试分布式系统总是很困难。当你使用的服务使用广泛的、通用的错误消息时,这会变得更加困难。

OAuth2 有标准化的错误消息,但它们在告诉你正在发生的事情方面与上面标题中的示例一样有用(顺便说一下,这是 OAuth 标准推荐的错误消息之一)。

你可能会争辩说 OAuth 是一个标准并且每个 API 都有文档,那么有什么可以调试的呢?

很多。我无法告诉你文档出错的频率。或者缺少一个细节。或者还没有更新最新的变化。或者当你第一次看到它们时你错过了什么。我们实施的 80% 的 OAuth 流程在首次实施时都存在一些问题,需要调试。

在我调试 OAuth 流程时 Randall 是如何观察我的?XKCD

某些流程也会因看似随机的原因而中断:例如,如果你传入 PKCE 参数,LinkedIn OAuth 就会中断。你得到的错误?“客户端错误 - 无效的 OAuth 请求。” 那是……告诉?我们花了一个小时才明白传递(可选,通常被忽略)PKCE 参数是中断流程的原因。

另一个常见错误是发送的范围与你在应用程序中预注册的范围不匹配。(预注册范围?是的,现在很多 API 都需要这样做。)这通常会导致出现有关范围存在问题的一般错误消息。呃。

6、在 API 之上构建的繁琐审批

事实是,如果你通过使用他们的 API 构建其他系统,你可能处于较弱的位置。你的客户要求集成,因为他们已经在使用其他系统。现在你需要让他们开心。

公平地说,许多 API 都是自由的,并为开发人员提供简单的自助服务注册流程来注册他们的应用程序并开始使用 OAuth。但是一些最流行的 API 在你的应用程序公开并且可以被任何用户使用之前需要进行审查。同样,公平地说,大多数审核过程都很正常,可以在几天内完成。就最终用户的安全性和质量而言,它们可能是净收益。

但一些臭名昭著的例子可能需要数月才能完成,有些甚至需要你签订收入分成协议:

  • 如果你想访问包含更敏感的用户数据(例如电子邮件内容)的范围,Google 需要进行“安全审查”。我们听说这些审核可能需要数天或数周才能通过,并且你需要付出大量的工作。
  • 想要与 Rippling 集成?准备好接受他们的 30 多个问题和安全预生产筛选。我们听说访问需要几个月的时间(如果你获得批准)。
  • HubSpot、Notion、Atlassian、Shopify 以及几乎所有其他拥有集成市场或应用程序商店的人都需要经过审查才能在其中列出。有些评论很温和,有些则要求你提供演示登录、视频演练、博客文章(是的!)等等。但是,在市场或商店中列出通常是可选的。
  • Ramp、Brex、Twitter 和许多其他公司没有面向开发人员的自助注册流程,需要你填写表格以进行手动访问。许多人很快就能处理请求,但我们仍在等待数周后的回复。
  • Xero 是货币化 API 的一个特别极端的例子:如果你想超过 25 个连接帐户的限制,你必须成为 Xero 合作伙伴并将你的应用程序列在他们的应用程序商店中。然后,他们将从该商店产生的每条线索中(截至撰写本文时)收取 15% 的收入。

7、OAuth 安全性很棘手并且是一个动态变化的目标

随着攻击被发现,可用的 Web 技术不断发展,OAuth 标准也发生了变化。如果你希望实施当前的安全最佳实践,OAuth 工作组为你提供了一份相当冗长的指南。如果你使用的 API 目前仍在使用 OAuth 1.0a,你就会意识到向后兼容性是一场永无止境的斗争。

幸运的是,安全性随着每次迭代而变得更好,但这通常是以开发人员的更多工作为代价的。即将推出的 OAuth 2.1 标准将使一些当前的最佳实践成为强制性的,包括强制性的 PKCE(目前只有少数 API 需要这个)和对刷新令牌的额外限制。

图片

至少 OAuth 已经实现了双因素身份验证模型。XKCD

随着访问令牌的过期和刷新令牌的兴起,可能已经迎来了最大的变化。从表面上看,这个过程似乎很简单:每当访问令牌过期时,用刷新令牌刷新它并存储新的访问令牌和刷新令牌。

实际上,当我们实现这个时,我们必须考虑:

  • 竞争条件:我们如何确保在刷新当前访问令牌时没有其他请求运行?
  • 如果你在一定天数内未使用刷新令牌(或者如果用户已撤销访问权限),某些 API 也会使刷新令牌过期。预计一些刷新会失败。
  • 某些 API 会在每次刷新请求时向你发出一个新的刷新令牌……
  • 但有些人也默默地假设你会保留旧的刷新令牌并继续使用它。
  • 一些 API 会以绝对值告诉你访问令牌过期时间。其他人只是相对“从现在开始的几秒钟”。还有一些,例如 Salesforce,不会轻易泄露此类信息。

8、最后:还没有谈到的事情

遗憾的是,我们只是触及了 OAuth 实施的皮毛而已。现在,OAuth 流程已经运行并且获得了访问令牌,这时候需要考虑:

  • 如何安全地存储这些访问令牌和刷新令牌。它们就像你用户帐户的密码。但是散列不是一种选择;你需要安全、可逆的加密。
  • 检查授予的范围是否与请求的范围匹配(某些 API 允许用户更改他们在授权流程中授予的范围)。
  • 刷新令牌时避免竞争条件。
  • 在提供商端,检测用户撤销的访问令牌。
  • 让用户知道访问令牌已过期,以便他们可以在需要时重新授权你的应用程序。
  • 如何撤销你不再需要的访问令牌(或用户要求你根据 GDPR 删除的访问令牌)。
  • 可用 OAuth 范围的更改、提供程序错误、缺少文档等。

原文链接:https://www.nango.dev/blog/why-is-oauth-still-hard


责任编辑:武晓燕 来源: 51CTO技术栈
相关推荐

2023-10-30 07:24:18

IT项目DevOps

2017-08-08 16:38:50

IT敏捷devops

2014-07-16 09:45:36

DOS

2022-02-14 13:59:47

数据数据孤岛大数据

2020-07-29 07:05:00

DevSecOps

2012-03-07 13:43:59

Objective-C

2022-09-19 00:08:22

人工智能机器交通管制

2016-12-16 12:54:44

数据挖掘大数据

2016-12-13 19:47:31

大数据

2021-03-02 16:25:13

手机iPhone安卓

2023-08-13 19:45:12

DNS

2021-06-25 11:19:04

LinuxWindows操作系统

2021-04-03 12:39:20

SQL数据库编程语言

2021-06-29 06:54:56

约会软件算法应用程序

2010-08-06 10:29:56

苹果

2017-05-25 12:04:58

云计算安全云数据

2014-07-14 09:58:18

Objective-CiOS学习

2021-07-26 14:50:03

人工智能算法云计算

2023-11-06 11:02:32

2015-11-13 11:02:35

点赞
收藏

51CTO技术栈公众号