一、OIDC协议介绍
1.OIDC简介
OpenID Connect(简称OIDC)是一种安全认证机制,第三方应用连接到身份认证服务器(Identify Service)获取用户信息,并把这些信息以安全可靠的方式返回给第三方应用。
OAuth2.0通过Access Token作为向第三方应用授权访问自身资源的凭证。OpenID Connect对OAuth2.0进行协议进行了扩展,通过扩展的ID Token字段,提供用户基础身份信息,ID Token使用JWT(JSON Web Token)格式进行封装,提供自包含性、防篡改机制,可以安全的传递给第三方应用程序并容易被验证。除了ID Token,还可以通过Access Token从认证服务的UserInfo Endpoint接口获取更详细的用户信息。
2.发展历史
2014年,OIDC规范发布。
2015年,OIDC认证计划启动。
2021年,OIDC联合规范第三实施者草案获得批准。
2022年,OIDC注销规范得以确定。
从这些时间点我们可以看出,OIDC的发展也是一个漫长且历经考验的过程,相对CAS、Oauth之类的协议,他具有长足的优势才能在的检验之后应用到大众的生活中,前面我们讲了一些用于单点登陆的身份协议,比如我们熟知的Oauth协议,Oauth从授权的角度来讲已经很完善了,为什么还会出现基于Oauth 2.0的OIDC协议呢,我们下面来进行介绍
3.为什么会出现OIDC?
大家已经学习过Oauth了,而且在生活中Oath的使用也相当广泛,而且相比于其他协议,Oauth安全性也有很大的提高,那么Oauth已经算是不错了,为什么还会有OIDC的出现呢,因为在Oauth协议的认证流程里,强调的是针对授权、授权范围以及给客户端哪些信息,并没有对用户有特殊的验证机制,换句话说,在Oauth流程中,它的重点是授权,那么OIDC呢,是认证。打个不太恰当的比方,Oauth只是门上插了一把钥匙,谁都可以打开这扇门,OIDC是指纹锁,只有特定的用户才可以打开。
4.OIDC和OAuth2.0的区别
Oauth流程注重的是授权,是验证统信实体是否有权限访问资源的过程,即“用户能做什么”,OIDC更注重认证的过程,确保通信实体是其所声称的实体,即“是哪一个用户”。
①OIDC流程中,授权服务器验证成功会响应会返回一个ID令牌,这在Oauth里是没有的。
②OIDC流程中客户端请求会在请求范围参数中包含字符串“openid”,当然,基本的OIDC架构是这样的,这一条并不绝对,因为随着OIDC的普及,我们也看到了一些重新开发过的OIDC实现,是没有这一部分的
③在Oauth的认证流程里,对于响应的令牌格式是没有规定,但是OIDC规定了令牌的格式为JWT。其实在实际应用的时候,很多Oauth其实也用的是JWT格式的令牌
5.OIDC协议前置知识
客户端:客户端指的是用户访问的web应用或者移动应用。也叫RP。
用户代理:用户代理指的是用户用于访问客户端的工具,通常为浏览器。
授权范围(scope):OIDC规范明确定义了客户端向认证服务器发起授权请求时必须在请求的scope参数中声明授权范围。
ID令牌(id_token):认证服务器验证用户身份后,除了向客户端返回响应令牌和刷新令牌,还会返回一个标识令牌所有者的ID令牌(id_token)。
响应类型(response_type):响应类型请求参数response_type告知授权服务器所需的授权处理流程,包括从使用的端点返回的参数。
6.OIDC认证协议认证流程
上面是从OIDC规范里扒的认证流程图,刚刚我们说了这里面的OP和RP。
RP就是客户端,也就是供用户访问的web应用,OP就是身份认证提供者,也可以说是认证服务器,用于对用户和客户端进行身份验证并颁发令牌。这里展示的是通常情况下用户不能看到的部分,也就是在认证流程中,用户代理访问的web应用或者移动应用与认证服务器之间的交互。
在OIDC协议规范里定义了三种授权流程,分别是授权码模式、隐式身份验证流程(在有些地方也将他叫做简化模式)和混合流程身份验证,下面我们来进行介绍。
授权码模式
下面是我根据OIDC授权码模式画的一个简单示意图,里面省略了状态码、授权码、令牌校验的部分。这个流程呢简单分为下面几个步骤:
1.用户使用用户代理访问一个客户端,也就是说我们用户通过浏览器来访问一个应用,应用校验用户是否登录。
2.应用就会将我们的浏览器重定向到认证服务器去进行认证。
3.浏览器重定向到认证服务器之后向认证服务器请求授权,这个地方图里省略掉了用户输入凭证的步骤。
4.当认证服务器验证用户凭证之后会返回一个授权码code,一般来讲是直接拼接重定向参数里的。
5.用户代理又被重定向到了web应用,这个时候请求里面包含授权码。
6.应用收到这个授权码,又用这个授权码向认证服务器发起请求。
7.在这里的①这个位置,这个地方认证服务器会验证一个state参数,这个参数的值其实是个随机值,作用主要用来防范CSRF,但在有一些oidc实现里删除了这个参数。
8.接下来认证服务器就向应用返回令牌,这里的令牌除了可能包含访问令牌和刷新令牌外还会有ID令牌,这个地方就有第二个注意的点,一般情况下,应用收到令牌之后,会对解析令牌然后对其中的参数进行校验,以确定令牌的准确性。
9.客户端使用访问令牌向资源服务器发起请求获取相应的资源
10.资源服务器返回受保护资源。
授权码模式简单流程图
代码示例
下面是认证流程里面的一部分代码示例。
1.客户端一般请求示例代码:
2.认证服务器返回授权码一般示例:
3.认证服务器响应令牌的一般示例:
简化模式
简化模式还是分为下面几个步骤,我们还是看下面的流程图来进行理解。
①用户代理向客户端发起请求。
②客户端将用户代理重定向到认证服务器。
③用户输入账号密码认证服务器进行验证。
④认证服务器直接把令牌返回给了用户代理。
⑤用户代理携带令牌发起请求。
简化模式认证流程图
简化模式的弊端:
①由于认证服务器直接把令牌返回给了用户代理,而且用户代理的交互和通信对于我们用户来说又是可见的,也就是说,我们可以从浏览器里直接去获取令牌,这个地方,就会造成令牌泄露。
②在简化流程里是没有刷新令牌的,如果令牌过期或者被吊销之后,需要重新在认证服务器进行认证来获取新的令牌
由授权流程我们可以知道,拿到正确的令牌之后,如果拼接的参数得当的话,其实就可以模拟正常的用户操作了,这也是我们说简化模式相对危险的原因。
7.OIDC认证流程对比
刚才说到了认证流程,具体的认证流程是由什么来决定的呢,除非我的身份提供商只支持一种认证流程。其实这一部分在我们一直提到的response_type参数里,oidc使用的认证流程是由授权请求里response_type参数的值决定的,具体的对应方式可以参考下面这个表格里的内容。左边第一列为用户代理的请求参数,如果在请求里直接请求令牌。那么就是简化模式,如果使用授权码就是授权码模式,如果既有授权码又有令牌就是混合流程。认证服务器根据收到的请求来进行判断决定用什么流程和返回对应的值。
OIDC认证流程对比图
在oidc里常见的扩展有三种、自动发现、表单回复和多种响应类型(response_type)。
1)OIDC协议扩展:OIDC Discovery
这个API主要是返回一个json结构的数据,其中包含OIDC提供者的配置信息,这样客户端就不需要硬编码oidc的服务接口信息。正常情况下路径为/.well-known/openid-configuration。
下图就是一个oidc实现的自动发现服务的一部分信息,从这些信息里我们可以看到该oidc提供者的认证、令牌、userinfo等接口,还可以看到它所支持的请求数据范围、支持的认证流程、还有一些令牌声明等信息。
通常这个接口的作用就是用于做信息收集的,一般来讲oidc身份提供商都会将这个接口公布出来让第三方应用访问,只不过里面包含的数据量和重要性会根据身份提供商对数据安全的重视程度有所不同。
某网站OIDC自动发现API-1
下面两张图分别是苹果和facebook的oidc实现的自动发现服务,相比上面这个那个,他们就显得谨慎了很多。只是公开了一些令牌声明支持的response_type等信息。
某网站OIDC自动发现API-2
某网站OIDC自动发现API-3
2)OIDC协议扩展:表单回复模式(OAuth 2.0 Form Post Response Mode)
在这个模式下,认证服务器的响应为一个html表单,响应的参数为html表单的值,浏览器在收到响应后进行解析,将值提取出来然后自动POST到客户端。
表单回复模式需要在请求里声明response_mode参数,并将form_post作为该参数的值,下面的图分别是请求id令牌的时候要求使用表单回复模式和来自身份提供商的响应,浏览器进行解析之后就向客户端发起PSOT请求。
请求包
认证服务器响应包
二、OIDC攻击面
OIDC协议目前来看是未来很长一段时间企业SSO的最佳选择,不管是国内外,各大企业包括各种平台都开始支持oidc接入,所以oidc相关的攻击面还是值得我们去探究的。
1.SSRF
认证服务器会根据redirect_uri参数值来进行跳转,如果我们修改数据包里的重定向参数值,而且认证服务器对这个值的校验不够严谨的情况下,就很容易产生SSRF漏洞,这就是个SSRF的请求包示例,开放的重定向也同样会导致这样的问题。
2.接口泄露
说到接口泄露不得不提我们之前说到的自动发现服务,我们知道,在自动发现服务接口里可以查询到一些其他的接口。一般来说安全意识不是很到位的部署是什么样的呢,比如一个网站,在他的主页面没有注册功能点,但是它写到了自动发现的接口里,可以被我们看到。通常一些做oidc信息收集的时候也习惯于检测这个页面是否存在。
3.令牌伪造
攻击者可能会生成虚假令牌或修改现有可解析的令牌内容从而获取不适当的访问权限。如果攻击者获取到了令牌,而且令牌校验方式不当的话,攻击者可以通过解析令牌来修改令牌内容,因为我们说了,授予权限范围取决于scope,那么我们就可以修改scope参数范围来获得更多的访问权限
4.令牌重放
通过重放一次性令牌(比如授权码)向认证服务器发起请求。
5.CSRF
引诱受害者点击恶意链接,通过伪装成受害者身份向认证服务器发起请求,一般对CSRF的防范就是在请求中添加一个值是随机值的state参数,然后授权服务器对这个参数进行验证。
6.验证绕过
认证服务器验证机制不严谨从而导致可以绕过验证。
三、OIDC漏洞案例
1.SSRF
CVE-2020-10770
影响版本RedHat Keycloak < 13.0.0
Keycloak是Red Hat出的一套为现代应用和服务提供身份验证和管理功能的软件,在13.0之前的版本,传到认证服务器的重定向uri,也就是咱们之前说过的认证之后,认证服务器会将浏览器重定向到的位置,对于用户来说是可控的,那么在我们提交请求的时候,修改这个参数,并且把这个参数值的位置指向我们的恶意服务器,恶意服务器就能够收到请求。
漏洞利用请求包
2.参数污染
在向github第三方应用发起请求验证的时候,在重定向uri里添加参数,认证服务器会将这个参数带到客户端,比如code参数,那么最后客户端收到的code参数就是两份,就像上面截图这样,一个code是我们自己构造的,一个code是在经过验证之后生成的正确的值,state也是我们自己输入的值也被带了过来,这样我们的code输入就会影响对原来正确的code的验证. 目前来看并没有特别好利用的点。
客户端接收到的请求
3.验证绕过
CVE-2023-22482
影响版本: argo CD <2.5.8
argo CD是用来将应用程序交付到k8s的持续交付开源工具,在2.5.8版本以前,对令牌验证不足导致的验绕过。
在认证服务器接收到id令牌后对令牌进行解析,复制给变量tokenstring。
令牌解析代码
解析之后的tokenstring里取各个声明的值来进行校验,后面这个位置对提取了aud然后验证,但是在对aud值进行验证的时候,并没有校验它的准确性,也就是说,即使这个aud值是一个不准确或不存在的值,在认证服务器进行令牌校验的时候也是没问题的。我们可以看到源码下面的注释也对这个逻辑提出了疑问。
令牌校验部分代码
四、总结
相对其他协议的话OIDC协议的漏洞会更加难以利用一些,,但是由于oauth和oidc的共通性,大部分在oauth协议上存在的漏洞也可能会出现在oidc部署上,只不过目前我们看到的oidc实现很大一部分都是经过二次开发过的,所以就算是同一个洞在不同的实现上面可能利用方式也不一样,在oidc的认证流程里面也有一些细节没有提到,比如机密客户端认证有client_id、client_secret参数啊、userinfo端点啊、令牌自省、刷新令牌啊、令牌校验过程。这一部分大家感兴趣的话可以去之前发布的身份协议白皮书里看看或者自己查一查。
OIDC学习相关链接:
https://openid.net/specs/openid-connect-core-1_0.html
https://www.oauth.com/playground/
https://www.rfc-editor.org/rfc/rfc6749
https://github.com/argoproj/argo-cd
https://security.lauritz-holtmann.de