【数据安全】OpenID Connect 释疑

Chinese, Simplified

OpenID Connect已成为互联网上单点登录和身份提供的领先标准。 它的成功公式:简单的基于JSON的身份令牌(JWT),通过OAuth 2.0流程提供,专为基于Web,基于浏览器和本机/移动应用程序而设计。

1.本地用户身份验证与身份提供商

应用程序通常需要识别其用户。简单的方法是为用户的帐户和凭证创建本地数据库。如果有足够的技术保养,这可以使其运作良好。但是,本地身份验证可能对业务不利:

  • 人们发现注册和帐户创建繁琐,这是正确的。消费者网站和应用程序可能因此而遭受废弃的购物车,这意味着业务和销售的损失。
  • 对于拥有许多应用程序的企业而言,维护单独的用户数据库很容易成为管理和安全的噩梦。您可能希望更好地使用IT资源。

这些问题的既定解决方案是将用户身份验证和配置委派给专用的专用服务,称为身份提供商(IdP)。

谷歌,Facebook和Twitter,互联网上的许多人都注册,为他们的用户提供这样的IdP服务。通过将登录与这些IdP集成,消费者网站可以极大地简化用户入职。

在企业中,理想情况下,这将是一个内部IdP服务,供员工和承包商登录内部应用程序。集中化具有相当大的好处,例如更轻松的管理以及新应用程序可能更快的开发周期。你可能会问:这不会造成单点故障吗?不,不是在为冗余构建IdP服务时。

2.进入OpenID Connect



OpenID Connect于2014年发布,不是IdP的第一个标准,但在可用性和简单性方面绝对是最好的,从SAML和OpenID 1.0和2.0等过去的工作中汲取了教训。

OpenID Connect成功的公式是什么?

  • 易于使用的身份令牌:客户端接收以安全的JSON Web令牌(JWT)编码的用户身份,称为ID令牌。 JWT的优雅和便携性以及对各种签名和加密算法的支持非常受欢迎。这一切使得JWT在ID令牌工作中表现突出。
  • 基于OAuth 2.0协议:ID令牌通过标准OAuth 2.0流程获得,支持Web应用程序以及本机/移动应用程序。 OAuth 2.0还意味着拥有一个用于身份验证和授权的协议(获取访问令牌)。
  • 简单性:OpenID Connect非常简单,可以与基本应用程序集成,但它还具有满足苛刻的企业要求的功能和安全选项。

3.身份令牌



ID令牌类似于标识JWT格式的身份证的概念,由OpenID提供商(OP)签名。要获得一个身份令牌,客户端需要通过身份验证请求将用户发送到他们的OP。

ID令牌的功能:

  • 断言用户的身份,在OpenID(sub)中称为subject。
  • 指定颁发机构(iss)。
  • 是为特定受众生成的,即客户(aud)。
  • 可能包含一个nonce(nonce)。
  • 可以指定何时(auth_time)以及如何在强度(acr)方面对用户进行身份验证。
  • 有发放(iat)和到期时间(exp)。
  • 可能包含有关主题的其他请求详细信息,例如姓名和电子邮件地址。
  • 是经过数字签名的,因此可以由目标收件人进行验证。
  • 可以选择加密以保密。

ID令牌语句或声明包装在一个简单的JSON对象中:

{

  “sub”:“爱丽丝”,

  “iss”:“https://openid.c2id.com”,

  “aud”:“client-12345”,

  “nonce”:“n-0S6_WzA2Mj”,

  “auth_time”:1311280969,

  “acr”:“c2id.loa.hisec”,

  “iat”:1311280970,

  “exp”:1311281970

}



ID令牌头,声称JSON和签名被编码为基本64位URL安全字符串,以便于传递 arround,例如作为URL参数。

eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ.ewogImlzcyI6ICJodHRw

Oi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5NzYxMDAxIiw

KICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZfV3pBMk1qIi

wKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5NzAKfQ.ggW8hZ

1EuVLuxNuuIJKX_V8a_OMXzR0EHR9R6jgdqrOOF4daGU96Sr_P6qJp6IcmD3HP9

9Obi1PRs-cwh3LO-p146waJ8IhehcwL7F09JdijmBqkvPeB2T9CJNqeGpe-gccM

g4vfKjkM8FcGvnzZUN4_KSP0aAp1tOJ1zZwgjxqGByKHiOtX7TpdQyHE5lcMiKP

XfEIQILVq0pc_E2DzL7emopWoaoZTF_m0_N0YzFC6g6EJbOEoRoSK5hoDalrcvR

YLSrQAZZKflyuVCyixEoV9GfNQC3_osjzw2PAithfubEEBLuVVk4XUVrWOLrLl0

nx7RkKU8NXNHq-rvKMzqg



您可以在RFC 7519中阅读有关JWT数据结构及其编码的更多信息。

4.如何申请ID令牌



既然我们知道ID令牌是什么,那么OpenID Connect中称为依赖方(RP)的客户端如何请求?

身份验证必须在身份提供者处进行,身份提供者将检查用户的会话或凭据。为此,需要受信任的代理,此角色通常由Web浏览器执行。

浏览器弹出窗口是Web应用程序将用户重定向到IdP的首选方式。 Android或iOS等平台上的移动应用程序应为此目的启动系统浏览器。嵌入式Web视图不受信任,因为没有什么可以阻止应用程序窥探用户密码。用户身份验证必须始终发生在与应用程序(例如浏览器)分开的可信上下文中。

请注意,OpenID Connect未指定用户应如何进行实际身份验证,这由提供商决定。

通过OAuth 2.0协议请求ID令牌,该协议本身取得了巨大成功。 OAuth最初被设计为一种简单的授权机制,方便应用程序获取Web API或其他受保护资源的访问令牌。它具有针对所有应用程序类型设计的流程:传统的基于服务器的Web应用程序,仅浏览器(JavaScript)应用程序以及本机/移动应用程序。

那么获取ID令牌的流程或路径是什么?

  1. 授权代码流 - 最常用的流程,适用于传统的Web应用程序以及本机/移动应用程序。涉及到/来自OP的初始浏览器重定向以进行用户认证和同意,然后是第二个反向通道请求以检索ID令牌。此流程提供最佳安全性,因为令牌不会泄露给浏览器,客户端也可以进行身份​​验证。
  2. 隐式流 - 适用于没有后端的基于浏览器(JavaScript)的应用程序。使用来自OP的重定向响应直接接收ID令牌。此处不需要反向频道请求。
  3. 混合流 - 很少使用,允许应用程序前端和后端彼此分开接收令牌。本质上是代码和隐式流的组合。

OpenID Connect规范提供了三种流程的良好比较,这里以简化形式再现。

Flow property Code Implicit Hybrid
Browser redirection step
Backend request step
Tokens revealed to browser
Client can be authenticated

5.ID令牌使用



除了基本登录之外,还可以使用ID令牌:

  1. 无状态会话 - 将ID令牌放入浏览器cookie可以实现轻量级无状态会话。这消除了在服务器端(在内存或磁盘上)存储会话的需要,这可能是管理和扩展的负担。通过验证ID令牌来检查会话。当令牌达到其发布时间戳(iat)之后的某个预定义年龄时,应用程序可以通过silent prompt = none请求简单地向OP请求新的时间戳。
  2. 将身份传递给第三方 - 当需要了解用户身份时,ID令牌可以传递给其他应用程序组件或后端服务,例如记录审计跟踪。
  3. 令牌交换 - 可以在OAuth 2.0授权服务器(draft-ietf-oauth-token-exchange-12)的令牌端点处交换ID令牌以获取访问令牌。当需要身份证件来获取访问权限时,有真实世界的场景,例如当您在酒店办理登机手续以获取房间钥匙时。令牌交换用于分布式和企业应用程序。

6.示例OpenID身份验证



现在,我们将使用授权代码流,通过一个最小的示例来说明如何从OP获取用户的ID令牌。这是传统Web应用程序最常用的流程。可以在OpenID Connect规范中找到隐式和混合流的示例。

代码流有两个步骤:

  Step 1 Step 2
Purpose 1. Authenticate user

2. Receive user consent
1. Authenticate client (optional)

2. Exchange code for token(s)
Via Front-channel request

(browser redirection)
Back-channel request

(app to web server)
To Authorisation endpoint Token endpoint
Result on success Authorisation code

(step 2 input)
ID token

(+ OAuth 2.0 access token)

代码流程:第1步



RP通过将浏览器重定向到OpenID提供程序的OAuth 2.0授权端点来启动用户身份验证。 OpenID身份验证请求本质上是一个OAuth 2.0授权请求,用于访问用户的身份,由scope参数中的openid值指示。

验证重定向到OP的示例:

HTTP/1.1 302

Found Location: https://openid.c2id.com/login?

response_type=code &

scope=openid &

client_id=s6BhdRkqt3 &state=af0ifjsldkj &

redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb



请求参数在URI查询中编码:

  • response_type:设置为 code  以指示授权代码流。
  • scope:用于在OAuth中指定所请求授权的范围。范围值openid表示对OpenID身份验证和ID令牌的请求。
  • client_id :OP上RP的客户端标识符。通过客户端注册API,开发人员控制台或其他方法向RP注册RP时,将分配此标识符。
  • state :RP设置的不透明值,用于维护请求和回调之间的状态。
  • redirect_uri:身份验证响应的RP回调URI。

在OP,通常通过检查用户是否具有有效会话(由浏览器cookie建立)来验证用户,并且如果没有,则通过提示用户登录来验证用户。之后,通常会询问用户是否同意登录RP。

然后,OP将使用授权代码(成功时)或错误代码调用客户端redirect_uri(如果访问被拒绝,或者发生了一些其他错误,则检测到这样的格式错误的请求)。

HTTP/1.1 302 Found

Location: https://client.example.org/cb?

code=SplxlOBeZQQYbYS6WxSbIA &

state=af0ifjsldkj



RP必须验证state 参数,并使用code继续下一步 - 交换ID令牌的代码。

代码流程:第2步



授权代码(authorisation code )是一个中间凭证,它对在步骤1中获得的授权进行编码。因此,它对RP不透明,只对OP服务器有意义。要检索ID令牌,RP必须将code提交给OP,但这次使用直接反向通道请求。这样做有两个原因:

在揭示令牌之前使用OP对机密客户端进行身份验证;

将令牌直接传递给RP,从而避免将它们暴露给浏览器。

代码交换发生在OP的令牌端点:

POST /token HTTP/1.1

Host: openid.c2id.com

Content-Type: application/x-www-form-urlencoded

Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW

grant_type=authorization_code &

code=SplxlOBeZQQYbYS6WxSbIA &

redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb



客户端ID和密钥通过Authorization标头传递。除了HTTP基本身份验证之外,OpenID Connect还支持使用JWT进行身份验证,JWT不会使用令牌请求公开客户端凭据,并且已过期,因此可提供更强的安全性。

令牌请求参数是表单编码的:

  • grant_type:设置为authorization_code。
  • code :从步骤1获得的代码。
  • redirect_uri 重复步骤1中的回调URI。

成功后,OP将返回一个带有ID令牌,访问令牌和可选刷新令牌的JSON对象:

HTTP/1.1 200 OK

Content-Type: application/json

Cache-Control: no-store

Pragma: no-cache

{ "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6IjFlOWdkazcifQ.ewogImlzc yI6ICJodHRwOi8vc2VydmVyLmV4YW1wbGUuY29tIiwKICJzdWIiOiAiMjQ4Mjg5 NzYxMDAxIiwKICJhdWQiOiAiczZCaGRSa3F0MyIsCiAibm9uY2UiOiAibi0wUzZ fV3pBMk1qIiwKICJleHAiOiAxMzExMjgxOTcwLAogImlhdCI6IDEzMTEyODA5Nz AKfQ.ggW8hZ1EuVLuxNuuIJKX_V8a_OMXzR0EHR9R6jgdqrOOF4daGU96Sr_P6q Jp6IcmD3HP99Obi1PRs-cwh3LO-p146waJ8IhehcwL7F09JdijmBqkvPeB2T9CJ NqeGpe-gccMg4vfKjkM8FcGvnzZUN4_KSP0aAp1tOJ1zZwgjxqGByKHiOtX7Tpd QyHE5lcMiKPXfEIQILVq0pc_E2DzL7emopWoaoZTF_m0_N0YzFC6g6EJbOEoRoS K5hoDalrcvRYLSrQAZZKflyuVCyixEoV9GfNQC3_osjzw2PAithfubEEBLuVVk4 XUVrWOLrLl0nx7RkKU8NXNHq-rvKMzqg"

"access_token": "SlAV32hkKG",

"token_type": "Bearer",

"expires_in": 3600,

}

ID令牌是JWT,在被接受之前必须由RP正确验证。

请注意,还包括 bearer access token。这是为了确保令牌响应符合OAuth 2.0规范。对于仅请求ID令牌的基本OpenID身份验证请求,此访问令牌是名义上的,可以安全地忽略。然而,访问令牌在请求访问UserInfo端点处的用户配置文件数据时也起作用。更多相关内容将在下一章中介绍。

7.索赔Claims(用户信息)

OpenID Connect指定一组标准声明或用户属性。 它们旨在根据请求向客户提供同意的用户详细信息,如电子邮件,姓名和图片。 语言标签支持本地化。

cope value Associated claims
email email, email_verified
phone phone_number, phone_number_verified
profile name, family_name, given_name, middle_name, nickname, preferred_username, profile, picture, website, gender, birthdate, zoneinfo, locale, updated_at
address address

客户可以通过两种方式申请索赔:

  • 整个声明类别按其作用域值(请参阅上表中的声明映射的作用域值)
  • 单独使用可选的声明请求参数。

通过简单地将范围设置为openid email来访问用户身份(ID令牌)和电子邮件的示例请求:

HTTP/1.1 302 Found

Location: https://openid.c2id.com/login?

response_type=code &

scope=openid%20email &

client_id=s6BhdRkqt3 &state=af0ifjsldkj &

redirect_uri=https%3A%2F%2Fclient.example.org%2Fcb



如果您是应用程序开发人员,请尊重用户的隐私,并将所请求的声明保持在最重要的位置。这将增加您转换用户的机会,并确保遵守最近的隐私法律。

请注意,即使用户允许应用程序访问其身份,他们也可能选择拒绝发布某些声明。应用程序应该能够优雅地处理这些决定。

声明格式为JSON:

{ "sub" : "alice",

"email" : "alice@wonderland.net",

"email_verified" : true,

"name" : "Alice Adams",

"given_name" : "Alice",

"family_name" : "Adams",

"phone_number" : "+359 (99) 100200305",

"profile" : "https://c2id.com/users/alice",

"https://c2id.com/groups" : [ "audit", "admin" ]

}



OpenID提供程序可以扩展标准JSON声明模式以包含其他属性。例如,企业可以定义诸如员工角色,经理和部门之类的声明。任何其他声明的名称都应以URL为前缀,以便为它们创建安全的命名空间并防止冲突。

8. OpenID Connect提供程序端点

Core endpoints Optional endpoints

8.1授权端点



这是OP服务器端点,其中要求用户进行身份验证并授予客户端对用户身份(ID令牌)的访问权限以及可能的其他请求详细信息,例如电子邮件和名称(称为UserInfo声明)。

这是用户通过用户代理与OP交互的唯一标准端点,该角色通常由Web浏览器承担。

8.2令牌端点



令牌端点允许客户端appf交换从授权端点接收的代码以获取ID令牌和访问令牌。如果客户端是机密的,则需要在令牌端点进行身份验证。

令牌端点它还可以接受其他OAuth 2.0授权类型来发出令牌,例如:

  • JWT断言
  • SAML 2.0断言

8.3 UserInfo端点



UserInfo端点将先前同意的用户配置文件信息返回给客户端。为此需要有效的访问令牌。

GET /userinfo HTTP/1.1

Host: openid.c2id.com

Authorization: Bearer SlAV32hkKG



UserInfo是JSON编码的,可以选择打包为签名或加密的JWT。

HTTP/1.1 200 OK

Content-Type: application/json

{

"sub" : "alice",

"email" : "alice@wonderland.net",

"email_verified" : true,

"name" : "Alice Adams",

"picture" : "https://c2id.com/users/alice.jpg"

}



8.4可选端点



OpenID Connect提供商可以拥有以下额外端点:

  • WebFinger  - 根据用户的电子邮件地址或其他详细信息,为给定用户启用OpenID Connect提供程序的动态发现。
  • 提供程序元数据 - 列出OP端点URL和它支持的OpenID Connect / OAuth 2.0功能的JSON文档。客户端可以使用此信息来配置对OP的请求。
  • Provider JWK set  - 包含JSON Web Key(JWK)格式的提供者公钥(通常为RSA)的JSON文档。这些密钥用于保护已颁发的ID令牌和其他工件。
  • 客户端注册 - 用于使用OP注册客户端应用程序的RESTful Web API。注册可能受到保护(需要预先授权)或开放(公共)。
  • 会话管理 - 使客户端应用程序能够检查登录用户是否仍与OpenID Connect提供程序进行活动会话。也方便退出。

 

9.规格在哪里?



该标准由OpenID基金会的一个工作组制作,包含一组文件,可在http://openid.net/connect/上进行探讨

10.常见问题



10.1 OpenID Connect如何与OAuth 2.0相关?



OAuth 2.0是一个用于获取受保护资源(如Web API)的访问令牌的框架。 OpenID Connect利用OAuth 2.0语义和流程允许客户端(依赖方)访问用户身份,该身份使用名为ID令牌的JSON Web令牌(JWT)进行编码。访问令牌有助于从OpenID提供者的UserInfo端点检索同意的配置文件详细信息(称为声明或属性)。

10.2 OpenID提供商如何对用户进行身份验证?

OpenID Connect完全取决于特定的IdP。实现者可以使用任何方法来验证用户,或者将两种方法结合起来以提高安全性(2FA)。

  • 用户名密码
  • 硬件令牌
  • 短信确认
  • 生物识别技术
  • 等等。

IdP可以在ID令牌中设置可选的acr和amr声明,以通知客户端用户如何被认证。

客户端也可以控制身份验证:

  • 可选的prompt = login参数将导致用户(重新)进行身份验证,即使他们具有IdP的有效会话(cookie)。
  • 通过支持各种身份验证强度的IdP,应用程序可以使用可选的acr_values参数请求更强的身份验证。

10.3什么是承载访问令牌(bearer access token)?



访问令牌类似于物理令牌或票证的概念。它允许持有者访问特定的HTTP资源或Web服务,该服务通常受范围限制并具有到期时间。

承载访问令牌易于使用 - 任何拥有一个令牌的人都可以调用受保护的资源。因此,必须始终通过安全通道(TLS / HTTPS)传递并安全存储。

OpenID Connect使用OAuth 2.0访问令牌,允许客户端应用程序从UserInfo端点检索同意的用户信息。

OpenID提供程序可以将访问令牌范围扩展到其他受保护资源和Web API。

原文:https://connect2id.com/learn/openid-connect

本文:http://pub.intelligentx.net/node/466

讨论:请加入知识星球或者小红圈【首席架构师圈】

SEO Title
OpenID Connect explained