最近想了一下,现在 AI 生产内容的能力很强,如果我再生产哪些低质的笔记,那还不如不写,所以之后我发文章,都尽量用最简洁的语言把内容说明白,至少优于 AI,不然干脆别写了...
OAuth
理解 OAuth 之前,我们先看看 OAuth 是干嘛滴 ------
简单来说,OAuth 就是用于第三方身份认证的,一个例子就是:我上线了一个平台,平台想支持飞书账号登录,那么这时候就需要 OAuth 发挥作用了
角色
那么整个过程就有 4 个角色,
我的系统 ------ 飞书开放平台 ------ OIDC(OpenID Connect)身份提供商 ------ 用户
其中,OIDC(OpenID Connect)身份提供商充当翻译官的角色,通过连接器(Connector)对接飞书账号系统
流程
飞书 Dex(后端) 浏览器 飞书 Dex(后端) 浏览器 #mermaid-svg-uo2X7lbEvU0RYuca{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-uo2X7lbEvU0RYuca .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-uo2X7lbEvU0RYuca .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-uo2X7lbEvU0RYuca .error-icon{fill:#552222;}#mermaid-svg-uo2X7lbEvU0RYuca .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-uo2X7lbEvU0RYuca .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-uo2X7lbEvU0RYuca .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-uo2X7lbEvU0RYuca .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-uo2X7lbEvU0RYuca .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-uo2X7lbEvU0RYuca .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-uo2X7lbEvU0RYuca .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-uo2X7lbEvU0RYuca .marker{fill:#333333;stroke:#333333;}#mermaid-svg-uo2X7lbEvU0RYuca .marker.cross{stroke:#333333;}#mermaid-svg-uo2X7lbEvU0RYuca svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-uo2X7lbEvU0RYuca p{margin:0;}#mermaid-svg-uo2X7lbEvU0RYuca .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-uo2X7lbEvU0RYuca text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-uo2X7lbEvU0RYuca .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-uo2X7lbEvU0RYuca .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-uo2X7lbEvU0RYuca .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-uo2X7lbEvU0RYuca .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-uo2X7lbEvU0RYuca #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-uo2X7lbEvU0RYuca .sequenceNumber{fill:white;}#mermaid-svg-uo2X7lbEvU0RYuca #sequencenumber{fill:#333;}#mermaid-svg-uo2X7lbEvU0RYuca #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-uo2X7lbEvU0RYuca .messageText{fill:#333;stroke:none;}#mermaid-svg-uo2X7lbEvU0RYuca .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-uo2X7lbEvU0RYuca .labelText,#mermaid-svg-uo2X7lbEvU0RYuca .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-uo2X7lbEvU0RYuca .loopText,#mermaid-svg-uo2X7lbEvU0RYuca .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-uo2X7lbEvU0RYuca .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-uo2X7lbEvU0RYuca .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-uo2X7lbEvU0RYuca .noteText,#mermaid-svg-uo2X7lbEvU0RYuca .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-uo2X7lbEvU0RYuca .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-uo2X7lbEvU0RYuca .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-uo2X7lbEvU0RYuca .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-uo2X7lbEvU0RYuca .actorPopupMenu{position:absolute;}#mermaid-svg-uo2X7lbEvU0RYuca .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-uo2X7lbEvU0RYuca .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-uo2X7lbEvU0RYuca .actor-man circle,#mermaid-svg-uo2X7lbEvU0RYuca line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-uo2X7lbEvU0RYuca :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 回调中的 code 经浏览器传递,属于正常的前端通道 app_secret 只在后端换取 token 时使用 GET /auth1302 到 /dex/auth?client_id=myapplication&...2点击"飞书登录"3302 到 open.feishu.cn/authen?app_id=cli_xxx&redirect_uri=dex/callback&state=...4打开飞书授权页并输入密码5302 到 dex/callback?code=XXX&state=...6请求 /dex/callback?code=XXX&state=...7POST /oauth/token(app_id + app_secret)8返回 access_token9
授权码流程将登录拆成两个通道:
- 浏览器 ------ 前端通道 ------ 授权服务器
- 服务器 ------ 后端通道 ------ 授权服务器
其中:
- 前端通道只传递一次性的、偷了也没用的东西,比如:client_id、state、code授权码、重定向的uri
- 后端通道传递长期有效的秘密:app_secret
安全分析
通过上面的流程,我们也就发现了 OAuth 安全的关键就是:app_secret。
这个 app_secret 是我们的应用发送给飞书的证明我们是这个应用的凭据。
那么如果 app_secret 泄露就会出现:
- 伪造身份调用飞书 API,能导出什么信息取决于飞书后台给当前应用开了什么权限
- 直接换取 access_token ,不需要 Dex (OIDC(OpenID Connect)身份提供商 ) ------ 一个原本被保护的动作,现在谁都能做
扩展一下思路,针对任意的 secret 泄露问题,可以从以下几个角度考虑:
- 这个凭据是什么的凭据
- 这个凭据本来是干什么的
- 现在我可以用这个凭据干什么
安全的 OAuth 设计
- code 不能被随意劫持,只能送到登记过的应用 ( OAuth 服务器控制)
- code 必须得是自己申请的 ------ 设备码绑定
- code 必须是一次性的、绑定指定应用
- 只能使用不可修改的唯一编码识别是谁
- secret 存储必须安全