授权的微妙之处:OAuth 2.0技术概述

Dodo IS信息系统由44种不同的服务组成,例如Tracker,饭店收银员或知识库等。为了不被多个帐户分散注意力,三年前,我们编写了Auth服务来实现传递身份验证,现在我们编写的第二个版本是基于OAuth 2.0授权标准的。该标准非常复杂,但是如果您具有包含许多服务的复杂体系结构,那么在开发自己的身份验证服务时,OAuth 2.0会派上用场。在本文中,我试图尽可能简单,清晰地告诉您有关该标准的信息,以节省您的研究时间。





 

验证任务



几十年前,在“锯成一体的时代”开始之初,就遇到了数十种服务的授权问题使用名为Auth的新服务解决了此问题。他帮助实现了跨各种服务的无缝身份验证,并将用户数据迁移到单独的数据库。 



Auth服务具有三个主要任务:



  • 所有系统服务的单点认证(SSO)服务不存储凭据,而是将其信任到一项专用服务。

  • 安全细粒度地获取资源安全,因为密码存储在一个地方并且尽可能安全。粒度,因为服务所有者可以根据来自身份验证服务的数据来配置对资源的访问权限。

  • . , , .





Auth的第一个版本是整体的一部分。它使用自己的协议与服务进行通信。当时需要这样的“方案”,但是经过几年的工作后出现了问题。



Auth是整体的一部分。因此,该服务与发布周期相关,这使得独立开发和部署成为不可能。此外,如果要部署Auth,例如在扩展服务时,则必须部署整个整体。



Dodo IS取决于Auth。在旧的实现中,外部服务在每个用户操作上调用Auth来验证有关它的数据。如果Auth由于某种原因而卡住,这种紧密的绑定可能导致整个Dodo IS停止工作。



验证取决于Redis...而且,它足够强大-Redis的故障将导致Auth的崩溃。我们使用Azure Redis,其规定的SLA为99.9%。这意味着该服务每月最多可能无法使用44分钟。这样的停机时间是不允许的。



Auth的当前实现使用其自己的身份验证协议,而无需依赖标准。在我们的大多数服务中,我们使用C#(如果我们在谈论后端),并且在为协议维护库方面没有问题。但是,如果突然出现Python,Go或Rust的服务,那么针对这些语言的库的开发和支持将花费更多的时间并带来更多的复杂性。



当前的身份验证使用基于角色的基于角色的访问控制方案...通常,该角色将获得对特定服务的完全访问权限,而不是与特定功能绑定在一起。例如,在比萨店中,有副经理可以领导某些项目:草拟时间表或考虑原材料。但是我们没有授予该系统特定组件的权利。您必须授予对该服务的完全访问权限,以便员工可以访问任何会计组件的计划或设置。



问题促使我们设计和编写新版本的Auth。在项目开始时,我们花了3周时间研究授权和认证标准OAuth 2.0和OpenID Connect 1.0。 



注意... 夸张的是,该文章是对RFC的重述,必须对RFC进行多次重读才能了解周围的情况。在这里,我试图摆脱这种复杂性,并以简单,结构化,简洁的方式告诉所有事情,而不描述复杂的事情,例如,服务响应可能包含哪些符号。与RFC不同,阅读了一次之后,您便可以了解所有内容。我希望本文对选择实现身份验证服务的解决方案很有用,并节省时间,或者可能会让某人思考其需求。



什么是OAuth2.0?



我们决定通过检查可用的协议和技术来开始开发新的Auth。最常见的授权标准是OAuth2.0授权框架。 



该标准于2012年采用,并且在8年多的时间里对该协议进行了更改和补充。RFC如此之多,以至于原始协议的作者决定编写OAuth 2.1,它将对OAuth 2.0的所有当前更改合并到一个文档中。当他处于选秀阶段时RFC 6749中



描述了OAuth的当前版本我们将对其进行分析。 



OAuth 2.0是一个授权框架。


它描述了如何实现服务之间的通信以确保安全授权。对许多细微差别进行了足够详细的描述,例如,节点之间的交互流程,但是有些细微差别要由特定的实现方式来决定。



特征:



  • 将用户实体与请求访问的应用程序分开由于这种分离,我们可以将应用程序权限与用户权限分开管理。 



  • 代替通常的具有一定权限和生存期的登录名和密码,我们可以使用随机生成的字符串令牌来访问资源

  • 您可以根据自己的意愿而不是预先确定的一组权限来尽可能精确地发布权限。



让我们仔细看一下功能。



的角色



OAuth 2.0定义了四个角色:



  • 资源所有者是有权访问受保护资源的实体。实体可以是最终用户或某种系统。受保护的资源是HTTP终结点,可以是任何东西:API终结点,CDN上的文件,Web服务。

  • 资源服务器-存储资源所有者有权访问的受保护资源的服务器。

  • 客户这是一个应用程序,它代表资源所有者并获得他的许可-授权,请求访问受保护的资源。 

  • 授权服务器-在成功获得资源所有者的授权后,向客户端颁发令牌以访问受保护资源的服务器。



交互中的每个参与者可以组合多个角色。例如,客户端可以同时是资源所有者,并请求访问其自己的资源。我们将进一步考虑交互方案。



重要提示:客户必须事先向服务注册。怎么做?



客户注册



您可以根据特定实现具体情况选择客户端注册的方法,例如,手动或服务发现。但是,在注册期间使用任何方法,除了客户端ID之外,还必须指定2个参数:重定向URI和客户端类型。



重定向URI-成功授权后资源所有者将发送到的地址。除授权外,该地址还用于确认申请授权的服务所声称的身份。



客户端类型-决定您如何与之交互的客户端类型。客户的类型取决于其安全存储其授权凭证的能力-令牌。因此,只有两种类型的客户端:



  • Confidential — , . , web-, backend.

  • Public — . , , .





OAuth 2.0中的令牌是对客户端不透明的字符串。通常,字符串看起来像是随机生成的-它的格式对客户端来说无关紧要。令牌是访问某些内容(例如,访问受保护的资源(访问令牌)或新令牌(刷新令牌))的密钥。



每个令牌都有其自己的生命周期。但是刷新令牌应该有更多,因为它用于获取访问令牌。例如,如果访问令牌的生命周期约为一个小时,则刷新令牌可以保留整整一周的时间。 



刷新令牌是可选的,仅适用于机密客户端... 使用可选令牌,在某些实现中,访问令牌的生存期非常长,并且完全不使用刷新令牌,以免打扰更新。但这并不安全。如果访问令牌已被破坏,则可以重置它,并且服务将使用刷新令牌接收新的访问令牌。如果没有刷新令牌,那么您将需要再次执行授权过程。



为访问令牌分配了一组特定的访问权限,该权限在授权期间发布给客户端。让我们看看OAuth 2.0中的权限是什么样的。



访问权



访问权限作为范围颁发给客户端。范围是由空格分隔的字符串-范围令牌组成的参数。



每个范围令牌代表授予客户的特定权限。例如,作用域令牌doc_read 可以提供对资源服务器上文档的读取访问权限,并employee 仅对公司员工提供对应用程序功能的访问权限。最终范围可能如下所示:email doc_read employee



在OAuth 2.0中,我们会自己创建范围令牌,并根据需要对其进行自定义。范围令牌名称仅受幻想和两个ASCII字符-"和限制\



在客户端注册阶段,在授权服务设置中,默认情况下为客户端提供标准范围。但是客户端可以从授权服务器请求除标准范围外的其他范围。根据授权服务器上的策略和资源所有者的选择,结果范围可能看起来非常不同。将来,在授权客户端之后,资源所有者可以在不重新授权服务的情况下取消某些权利,但是为了发出其他权限,将需要对客户端进行重新授权。



抽象的OAuth 2.0。使用访问令牌的流程



我们研究了角色,研究了令牌的类型,以及范围。让我们看一下提供对服务的访问的流程。



下面是参与者之间交互的抽象图(或流程)。此图中的所有步骤均严格从上至下执行。让我们更详细地分析。







  • 客户端发送请求以访问所需的资源所有者。

  • 资源所有者将授权授权返还给客户端,以确认资源所有者的身份及其对客户端请求访问的资源的权利。根据流程,这可以是令牌或凭证。

  • 客户端将在上一步中获得的授权授予发送到授权服务器,期望从中获得访问令牌来访问受保护的资源。 

  • 授权服务器确保授权授权有效,然后将访问令牌发送回客户端。

  • 客户端收到访问令牌后,会向资源服务器请求受保护的资源。 

  • 资源服务器确保访问令牌正确,然后提供对受保护资源的访问。



客户获得资源所有者的批准,并在此基础上授予客户对资源的访问权限。这很简单。如果将刷新令牌添加到此方案中会容易吗?



抽象的OAuth 2.0。使用刷新令牌的流程



此图中省略了第一步和第二步-它们与上面的抽象流程图没有什么不同。







方案更详细:



  • 客户端附带了对授权服务器的授权授权,并要求向其提供访问令牌和刷新令牌。

  • Authorization server , authorization grant access token refresh token.

  • Client access token , — invalid token error.

  • , authorization server refresh token access token . 

  • access token, refresh token, refresh token. 



grant?



授予是代表资源所有者成功授权客户端的数据,客户端用来获取访问令牌。



例如,当我们在某处通过Google进行身份验证时,会在您眼前弹出一条通知。它说某某服务想要访问有关您或您的资源的数据(显示请求的作用域令牌)。此通知称为“同意屏幕”。



当我们单击“确定”时,相同的授权将进入数据库:记录的数据表明某某用户已经对该某某服务进行了某某访问。客户端接收某种成功的身份验证标识符,例如字符串,该标识符与数据库中的数据相关联。



有4 + 1种方式获得资助-资助类型:



  • Authorization code — confedencial — web-.

  • Client credentials — confedential , , .

  • Implicit — public-, redirection URI (, ), authorization code grant PKCE (Proof Key for Code Exchange — , , token , . — RFC 7636).

  • 资源所有者密码凭证OAuth 2.0安全性RFC 6819中,此授予类型被认为是不可靠的。如果更早,则仅允许将其仅用于将服务迁移到OAuth 2.0,目前根本不允许使用。

  • 设备授权(在RFC 8628中添加)-用于授权可能没有Web浏览器但可以在Internet上运行的设备。例如,这些是控制台应用程序,智能设备或智能电视。



只有授权码(带有PKCE),客户端凭据设备授权授权可以被认为是相关的,但我们将考虑所有内容。我们将按理解的复杂性顺序考虑授予。



Client credentials grant flow



它具有最简单的流程,让人想起任何服务的常规授权。它使用客户端的凭据(即客户端ID和客户端密码)执行-用户的登录名和密码类似。由于身份验证需要必须适当存储的客户机密,因此该流程只能由机密客户使用。







该方案很简单:通过传递客户端ID和客户端密钥在授权服务器上对客户端进行身份验证。作为响应,它收到一个访问令牌,已经可以使用它访问所需的服务。



当客户端尝试访问其自己的资源或先前与授权服务器达成协议的资源时,需要此流程。例如,服务A需要不时转到服务B,并在那里更新有关网络中比萨店数量的数据。



资源所有者密码凭证流



根据此RFC中描述的当前安全建议,由于明显的安全问题,完全不建议使用此流程。





在此流程的说明中,有两个客户端,理论上应该有一个客户端和一个授权服务器。



资源所有者例如通过客户端上的表单将其用户名和密码传输给客户端。客户端依次使用它来获取访问令牌(以及可选的刷新令牌)。



这里有个问题。资源所有者只是简单地获取并以清晰的形式将其用户名和密码提供给客户端,这是不安全的。它最初仅用于您信任的客户端或操作系统的一部分。后来,仅允许它从登录名和密码身份验证迁移到OAuth 2.0。当前的安全准则禁止使用它。 



授权码



目前最常见的流程。通常用于机密客户,但是随着PKCE引入了附加验证,它也可以用于公共客户。 



在此流程中,客户端与资源所有者之间的交互通过用户代理(浏览器)进行。用户代理有一个要求:它必须能够使用HTTP重定向。否则,资源所有者将无法访问授权服务器并获得授权返回。 







该流程比以前的流程更为复杂,因此我们将逐步对其进行分析。首先,让我们假设我们是资源所有者,并转到了在线学习服务的页面,该页面希望将学习结果保存到我们的云中。他需要访问我们的资源,例如云中的某个目录。我们单击“登录”,然后开始执行授权码授予流程:



  • 第一步,客户端使用用户代理将资源所有者重定向到授权服务器身份验证页面。在URI中,它指定客户端ID和重定向URI。重定向URI用于了解授权成功后资源所有者在何处返回(资源所有者将授予客户端请求的范围权限)。

  • user-agent, resource owner .

  • Resource owner , consent screen .

  • Resource owner user-agent URI, redirection URI. query- authorization code — , , resource owner . 

  • authorization code , access token ( refresh token, ).

  • authorization code, , access token ( refresh token). . 



如果我们想象我们代替资源所有者,那么我们只会看到重定向到授权服务器,进行身份验证,确认对“同意”屏幕的访问并将我们发送到已经运行的服务。例如,当我们使用Google,Facebook或Apple帐户访问服务时,我们会经历很多次。



下一个流程以此为基础。



隐性补助



这是对知道如何使用重定向URI的公共客户端的授权代码授予流程的优化。例如,对于JavaScript浏览器应用程序或移动应用程序。客户端与资源所有者之间进行交互的用户代理要求仍然存在:他必须能够使用HTTP重定向。



授权代码和隐式代码之间有一个主要区别:在成功获得资源所有者的授权后,我们立即收到访问令牌,而不是在上面接收授权代码和访问令牌。另外,出于安全原因,此处不使用客户端密钥-可以反汇编和检索应用程序。仅通过重定向URI检查真实性。







该图中的许多步骤与授权代码中的步骤相似,但我建议也对其进行详细分析。假设浏览器应用程序要将其设置保存在我们的Git存储库中。我们单击“登录到GitHub”,此时隐式流程开始:



  • 客户端使用用户代理和HTTP重定向将资源所有者重定向到授权服务器。在请求参数中,它传递了对客户端进行身份验证所需的客户端ID和重定向URI,然后返回资源所有者。

  • 通过用户代理与授权服务器进行通信来对资源所有者进行身份验证。同时,它确认向客户发出授权,他随身带来的客户ID。

  • grant ( «allow» consent screen), user-agent resource owner redirection URI. , URI fragment access token (URI fragment — , URI ‘#’).

  • user-agent. User-agent redirection URI web-, access token . , , , CDN.

  • Web- web- ( ), redirection URI, , .

  • User-agent , , web-hosted client resource, access token.

  • 生成的访问令牌用户代理仅转移到客户端。



这是一个复杂的流程。在实际场景中几乎没有用。但是它仍然可以在遗留项目中找到。



设备授权(RFC 8628)



从2012年到2019年,出现了许多不方便登录的智能设备。例如,每次打开资源时,在电视上输入复杂的用户名和密码都是很不方便的。在某些没有图形界面的设备(例如服务器操作系统)上,这是不可能的。在2019年8月,此流程仅在此类情况下出现。 



为了与设备授权授予流程一起使用,设备至少有3个要求:



  • 设备必须能够发出传出的HTTPS请求。

  • 设备必须能够向用户显示URI和ID。

  • 每个授权的设备都属于资源所有者,为了成功进行授权,资源所有者必须拥有另一个具有浏览器的设备才能转到指定的URI并输入指定的代码。







由于箭头的数量众多,该方案可能看起来很复杂。让我们逐步分析它,因为我们先分析了复杂的流。



假设我们正在尝试使用电视登录Web服务。我们看到按钮“以设备身份登录”,然后单击。此时,我们的设备流程开始:



  • 电视向授权服务器发出请求,并为其提供其客户端ID。

  • 授权服务器验证此类客户端已注册并且具有适当的授予类型。

  • , Authorization server device code, user code verification URI. Device code — , .

  • user code verification URI — resource owner. Redirection URI , QR- — .

  • , user code verification URI, .

  • resource owner. verification URI, user code, , scope . resource owner .

  • 一直以来,设备(第3点)都向授权服务器轮询其成功。设备再次使用其设备代码和客户端ID进入授权服务器,希望这次授权已通过。

  • 这次,当资源所有者确认向设备转移了必要的权限时,授权服务器将响应该请求返回访问令牌(如果由服务器设置和刷新令牌提供)。借助令牌,设备可以继续使用资源。



尽管箭头看起来很复杂,但是此流程也非常简单。如果您需要与设备进行交互(并且我们有很多设备:跟踪器,收银机,店面和其他设备),则应使用此流程。



代替输出



在本文中,我省略了许多细节,以便以最简单易用的方式讨论最重要的事情。例如,查询的类型,如何以及以何种形式传递参数,允许使用哪些字符作为值。 



如果您想更详细地研究该主题,那么我建议使用RFC 6749(用于OAuth 2.0)和RFC 8628(用于设备流)。您还可以检查OAuth资源中最新的RFC



如果这篇文章很有用,并且您想了解更多详细信息,请在评论中写,在接下来的文章中,我将讨论PKCE,OpenID Connect 1.0身份验证协议,我们对身份验证服务器的实现等。



有用的链接:






All Articles