这个bug可使用户以admin的身份进入博客后台(控制台),并且正常使用发布编辑文章,上传图片功能,具体如何触发我已邮件告诉你,请留意
以上是好心网友在发现了这个bug之后写的,以下是作者(snowykami)写的:以上变是事情的经过,不过非常感谢告知这个漏洞,十分甚至九分严重
先说问题:GitHub没有提供OIDC标准字段(不过人家是OAuth)和neo-blog的开发者(我)写的代码存在没有验证空值的问题,最终是因为我没有处理预期之外的空字符串导致的严重p0级事故
OIDC认证流程(授权码模式)
假设有web应用(neo-blog),用户浏览器,认证方(GitHub)三个角色
前置:
我们需要在认证方处创建应用,配置应用的回调url,获取client_id,client_secret
我们需要在应用处配置认证方的1.认证端点(authorization_endpoint),2.令牌获取端点(token_endpoint),3.用户信息端点(userinfo_endpoint),认证方提供的client_id和client_secret
在有的情况下,不一定是谁提供client_id,client_secret,两边设置一样就行,这个取决于软件和平台本身实现
首先,应用会使用身份提供者的
client_id
,redirect_uri
,state
创建一个可用于登录的链接给用户客户端,打开该链接会把用户引导至认证方的登录页面用户完成身份认证,认证方会把用户重定向到应用的回调接口,该接口通过浏览器GET请求,并在查询参数中附带了认证方提供的授权码(code)和state,该web应用可以在服务端拿到这个code和state
web应用服务端校验这个state是否是和之前的一致,然后使用上一步的code和预先配置的client_id,client_secret,redirect_uri作为表单参数,POST请求认证方提供的access_token端点,完成这一步可以拿到access_token
有了上一步的access_token,我们可以请求userinfo端点,获取到一个包含了用户信息的键值对map。
web应用拿到认证方提供的身份信息后,就可以和自己本地的用户系统进行一系列映射、匹配和绑定,自行给用户签发token(这一步有点像你百度绑定QQ号)
问题分析
纵观整个登录流程,OIDC是一步一步来的,其中我每一步请求都有校验,出错就会响应失败。但是问题就出在最后一步,我们拿到身份信息后的步骤。GitHub的是OAuth2,由于OAuth2并没有规定用户信息端点需要返回什么东西,所以各家平台的oauth2返回的用户信息字段或多或少有点差别,而我的代码是标准的OIDC认证,OIDC基于OAuth2扩展而来,规定了用户信息端点必须返回哪些字段。比如我们认证核心就是issuer和sub字段,issuer代表签发人,一般是平台的网站,sub代表该用户在平台上的一个唯一id,就比如issuer是https://qq.com,sub是你的QQ号。
接下来就是问题的核心了,GitHub返回的issuer、email和sub字段都是空的,在经过我的结构体绑定后变成了空字符串,而我代码的逻辑如下:
先根据issuer和sub进行查找,查找到绑定记录直接使用绑定用户登录
如果未找到绑定记录,且当前有用户登录,那么进行账号绑定
如果没有用户登录,那就用认证方提供的email字段,查找本地符合的用户进行绑
如果没查到,那就创建新用户
所以不出我所意料,第一个绑定GitHub的用户就是我自己,绑定了一个空字符串id。此后有其他用户使用GitHub登录,我们结构体绑定的Sub字段依旧是空值,按照逻辑流程的第一步会用issuer和sub去查找绑定记录,issuer为https://github.com,sub为""(空字符串),很自然这个空字符串就会查找到我的那条绑定记录。导致所有使用GitHub登录的用户都会登录到第一个绑定GitHub的用户上,也就是我的管理员账户
解决方案
在用户信息端点返回时进行空值检查,并单独对非标平台(例如GitHub)的用户信息字段进行重新映射,例如GitHub提供的唯一id字段是id,我们把id映射为sub。在处理完平台差异后进行issuer,sub,email字段的空值检查
在数据库层的操作函数里面,加上对空值的检查,如果查询参数为空值,直接返回未找到
oidc登录接口新增is_bind参数来区分绑定请求和登录请求
反思
对认证流程细节把控不足:未充分考虑不同认证方返回用户信息字段的差异,过于依赖标准oidc认证逻辑,导致GitHub返回空字符串字段时,代码逻辑出现漏洞。
代码逻辑的健壮性不够:用户信息处理环节未对空字符串等异常情况进行检查,导致错误绑定和登录行为。
安全风险重视不够:未充分意识到认证逻辑错误可能带来的安全风险,未进行严格的安全审查和测试。
兼容性测试不足:未对GitHub等外部认证平台的兼容性进行充分测试,未提前了解其OAuth2认证细节并进行适配。
其实最初我觉得大平台的oauth都是标准化的,没有去看github restful api文档,现在不会这么觉得了