iframe中oidc登陆失败
我把一个需要 OIDC 登录的站点单独打开时一切正常;但一旦嵌进别的网站的 iframe,就可能报错: oauth state does not correspond
根因是 iframe 场景下浏览器把关键的 cookie 给挡了,导致”保存的 state”丢了。
- OIDC 登录到底发生了什么?
1) 你的应用发起登录,浏览器跳转到配置的的第三方的权威的登录地址(如 google.com/oauth2/authorize) 2) google 登录成功后,浏览器跳回你的应用回调地址(redirect_uri),带回来一个 code 3) 你的应用用 code 去 google 验证,合法的法,换回 token,里面可能包含用户身份信息
- state 干嘛的?
state 可以理解成 “我这次登录请求的防伪码 + 订单号”。
上面第一步的时候,客户端生成一个 state (先存到 cookie 里面,iframe 就是这一步失败了),发起请求时带上。
google redirect 回来时,带回这个 state。
客户端比对:回来的 state,必须和刚才发起登录时存的 state 一致,才能继续后续处理。
- 不加 state 会有什么风险?
假设你的回调地址是 https://cmdb.example.com/oidc/callback
攻击步骤
1) 攻击者自己正常登录一次,拿到回调会用到的 code=ATTACKER_CODE 2) 攻击者把这个链接发给你,诱导你点: https://cmdb.example.com/oidc/callback?code=ATTACKER_CODE 3) 你一点,浏览器带着你的站点 cookie 访问回调 4) 如果你的应用不校验 state,它会把这个 code 当成“你发起的登录结果”,把你的浏览器会话登录成攻击者账号
后果
你接下来所有操作都记在攻击者账号下,你可能在攻击者账号里做敏感操作(绑定信息、生成 token、修改配置等)
- 为什么独立打开正常,iframe 里就 state mismatch?
关键点:在 iframe 里,OIDC 所在站点常常变成“第三方上下文”。
现代浏览器对第三方上下文越来越严格,经常出现: 第三方 cookie 被拦截,登录发起时保存的 state,回跳回来时读不到了。
-
解决思路(从稳到折中)
-
最稳方案:不要在 iframe 里做 OIDC 登录,改成新标签页/弹窗打开(避免第三方上下文)。
-
更实用的 iframe 方案:反向代理,让它“同站点”
用 Nginx 把 Chainlit 代理到你自己的域名路径下(例如 /chatops/),让浏览器认为它是第一方,cookie/session 更容易正常工作。
同时要把 OIDC 的 redirect_uri 配成同域路径。
- 能控制服务端时,配置方案:cookie SameSite=None; Secure
有时能缓解,但在越来越严格的浏览器策略下不一定稳定。