1
tanxnative 1 天前
抖音上徐庶说, 这样安全!
|
2
shakaraka PRO 首先,这种问题在 v2 算是日经贴的了,搜一下就有了,其次直接问 GPT 就有很标准的答案的。
另外我再回答一下吧 Access Token 是让网关去进行身份认证的,不需要查询数据库,数据库没有压力,高流量场景不需要查询 redis 、db 等,也支持分布式,同时 Access Token 不会授权很长时间 Refresh Token 是需要查询 db 的,因为要对用户进行一些业务逻辑判断,分析是否能够重新下发 Access Token |
3
ty29022 1 天前 一种工程上的 trade off
本质上是想把无状态的 jwt token 变成有状态的 然后把每次状态的查询成本摊到 n 秒一次(refresh token 的过期时间) |
4
zhlssg 1 天前
无感知续签,token 是有有效期的,Refresh 可以在用户过期时续签 token ,无需用户重新登录
|
6
shakaraka PRO @yiqiao #5 想要完全后端类决定前端生死的只能是 session 的模式。没有比这种掌控力更强了。token 模式多数用在互联网产品中。像是金融客户系统就多数是类似 session 模式的
|
7
cfancc 1 天前
问 ai 或者百度
|
8
zxjxzj9 1 天前
理论上一直用一个 token 来鉴权也不是不行,问题就在于 jwt 这样的无状态 token 不改秘钥不设置过期时间,token 发下去就会永久有效。为了让服务端有办法能让 token 过期但是又利用无状态特性,实践上把这一个 token 拆成两个,验证的时候用 access token ,让鉴权的时候不需要访问数据库直接端侧完成。refresh token 完全可以理解成一个 session id, 只要会话不过期服务端就可以给你续签,好处就是直接把请求 db 的次数用 access token 全压下去了。 这两个 token 也没明说非要用 jwt ,只不过如果要用的话全用 jwt 可以少造点轮子。
|
9
yeqizhang 1 天前 via Android 虽然是月经帖,但我还是没得出标准结论,之前有从网络安全来讲的,也见过像第三方授权如对接微信那种又是不一样的,今天又在这里说查不查数据库的……
|
10
zuixinwenyue 1 天前
只是表示讨论,国内好多大厂对外开放的 api 都是双 token 模式,肯定是有一定优势的,我说一下我自己的理解吧。
|
11
zuixinwenyue 1 天前
@zuixinwenyue 没想到拍了回车就回复了
|
14
zuixinwenyue 1 天前 @zuixinwenyue
先说一些传统的 token 模式有状态和无状态 1.有状态:cookie 或者 uuid 生成一个 token 放请求头里,这些都属于有状态。服务侧缓存 token 信息 2.无状态: jwt 本身就带了 token 的信息&用户信息; 分析一下痛点,可能举例不完善: 有状态: 每次请求进来需要查询缓存啊 or 数据库,影响性能 可以做判断 token 是否存在啊 用户是否登录过期啊 用户有没有被禁用 也可以做到用户信息发生修改 踢用户下线之类的操作 只允许一端登录啊。可控性非常大; 无状态: 无状态的话就不需要查询数据库了,从性能来讲肯定是比有状态要好的,服务侧拿到只需要验签就可以。 缺点也很明显,上面说到有状态能做的都不行 双 token 我自己感觉是折中了一下 在需要性能+用户可控方面折中,一般来讲 accessToken 是无状态的用于快速验证 过期时间较短,refreshToken 是有状态 用于判断用户信息之类的操作 过期时间较长。这样就可以在性能和用户可控方面折中啦。 以上是我的浅见 |
15
SethShi 1 天前
提一嘴.
JWT 没有双 token, 它只定义了 token 的格式 楼上说的国内大厂的那种是 OAuth 2.0 至于你要问的问题, 楼上的答案都差不多了, 当然不排除很多人是“为了遵守协议( OAuth2 )”而盲目使用双 Token |
16
zuixinwenyue 1 天前
网上说什么的都有 有说是为了让用户无感续签,之前做的项目是有状态的 每次用户请求进来都会给 token 续期。我之前面试也被问过这个问题 我回答的就是用户带 token 进来验证成功就续期一下 现在想起来问的应该是双 token 。但是我理解使用双 token 不是为了续签,更是为了追求性能+用户可控性一个折中的方案;
|
17
zuixinwenyue 1 天前
@SethShi oauth2.0 是提供授权码,最后用授权码换回来的就是双 token 。
|
18
Ketteiron 1 天前
@yeqizhang #9 标准结论一直都有啊,用不用 jwt 只看需不需要 jwt 。
jwt 实际上是拿 cpu 解密开销换取数据库查询开销,为了安全性可能会双 token(15 分钟危险期) or 单 token+redis(秒级封禁)。除此之外有非常多的组合方法,但各有侧重点没有高下之分,软件开发不存在通用最优解。 |
19
softlight 1 天前
看了下,access token 只需要校验 token 是否有效,无需外部依赖查询。Refresh Token 分发 Access Token 时,需要额外查询,比如用户是否被禁用, 权限是否发生变更,账号是否被封。 在性能和可控当中,做这个折衷选择
|
22
SethShi 1 天前
@zuixinwenyue 都是 OAuth 协议标准的定义呀
|
24
litchinn 1 天前
一个 token 怎么让用户无感续签呢
|
25
sentinelK 1 天前 Refresh Token 的存在,就是因为要验证其“续签 token 的合法性和合理性”
你可以把 Refresh Token ,看成是自动重新登录的“用户名+密码”。 当 token 对应的账户被封禁、密码修改等操作时,对应的 Refresh Token 也会同时作废。也就是当前用户的操作权限也就到这个 token 生命周期结束为止。 至于说为什么自动登录不使用用户名+密码作为参数。 因为,用户名+密码是最高级别的用户信息,不应该被保存和频繁录入、传输。 |
26
sentinelK 1 天前
至于说,为何不每次请求都验证 token 对应的用户合法性,这是基于性能的妥协。
|
27
sentinelK 1 天前 btw:JWT 是一种 token 的实现形式。
和“是否采用双 Token”、“是否遵循 OAuth 2.0”等话题风马牛不相及。 所以,“ jwt 续签为什么要使用双 token”严格来讲是个错误命题。 |
28
canteon 1 天前
这是一个球疼怪子弹的问题
|
29
photon006 1 天前
如果只有一个 accessToken ,快到期了,用户前几秒还在填信息,下一秒点提交跳登录页。。。What the fuck!!!
|
30
zxjxzj9 1 天前 @lusxh 操作上当然都可以,你把 refreshtoken 做成过期时间很长的 jwt ,每次校验 refresh 的时候也不用过数据库。问题就在于这样做拆分就没有意义了,直接用 access token 校验不就好了么。你这样问的就是,我不查数据库有没有办法维护一个 token 的状态,那答案肯定是否定的。
不过 oauth2.0 并没有规定这些乱七八糟的,这个框架只明确规定了客户端应该利用获取 access token 这个行为来获得第三方网站的授权,注意是第三方,而不是在客户端上直接输入第三方网站的密码来获取授权。access token 在标准里也就说了是一个授权字符串,refresh token 是获取 access token 的字符串,根本没人管你怎么验证。你实现成第三方客户端只要把 114514 填进 access token 发给你就算 Authorized ,refresh token 只要是 1919810 你就返回 114514 都没人管你。 只不过后面 jwt 等无状态 token 的技术出现了,大家就开始往这个标准上套,然后总结出一套最佳实践就是无状态 access token+有状态 refresh token ,其中无状态 access token 就可以直接用 jwt 的方式实现(也有不用 jwt 的,google oauth api 就不是 jwt )。这样不管是第一方还是第三方的验证,都可以在无状态和有状态验证的优缺点之间取得一个平衡。还有不少人其实连 oauth 2.0 一开始是给第三方授权的都不知道,第一方授权也这么写,然后不知道这标准为什么要这么定义,就去硬套说什么给用户无感刷新用,这就是为了凑个理由强行说了。你第一方对自己的客户端,直接把 refreshtoken 做成 jwt 一直无状态也没人管你,反正发行 token 的时候用户肯定要敲账号密码的,账号密码也都存在你这里,谁来管你呢? |
31
urlk 1 天前
jwt 本质上只是把用户 id 进行编码,加上域名用于验证,加上过期时间用于判断是否可用 主要信息传的还是用户 id
jwt 优于 cookie 和 session 的点在于 后者受限于浏览器机制限制,对同源策略不友好,在 app 等非浏览器环境下适配性更好, 在微服务架构中网关处理更加方便, 安全方面由于不在 cookie 中传输,所以天然防御 CSRF 攻击 单 jwt Token 续签流程,用的就是短过期时间 例如 30 分钟 + 长过期时间标记 例如 7 天, 当短过期时间过期: 拒绝请求,返回过期错误,要求前端用旧 Token 请求刷新接口, 长过期时间过期 则返回 401 要求重新登陆 至于 Refresh Token 刷新令牌是 OAuth 2.0 授权框架中的概念, 使用 Refresh Token 长有效期刷新 Access Token 短有效期, 比单 Token 机制更加安全 |
32
catamaran 1 天前
客户要求登出后 token 必须失效,直接又把 jwt 扔 session 里了🤣
|
36
zxjxzj9 1 天前 @litchinn 答案是其实根本就不需要续签,针对第一方应用的时候,验证信息(账号密码 passkey 等)全都保存在第一方后端里,发行任何 token 都需要完整信息验证,这种情况下是续签是为了续签而续签(降低数据库访问),是实际操作上的处理,而并非 refresh token 设计出来的本意。oauth 2.0 之所以设置成两个 token ,是因为标准上来说,oauth2.0 希望客户端无法知道第三方给的 access token 内部的具体细节,而给了 refresh token 就相当于第三方信任了当前客户端,并且留了一手可以随时撤销授权的能力。 在进行授权操作的时候,第三方完全可以不给 refresh token ,只给 access token (比方说第三方登录的时候只给一个 access token 来让当前客户端拿到用户名,不给继续访问后续信息的权限)。
|
37
lusxh OP @zxjxzj9 大家看看这老哥的答案。我也感觉,我自己写的系统为什么要用双 token ,没感觉双 token 那里好么,下次面试碰到这种问题,就这么回答了。
|
38
billbur 1 天前
我对双 token 的理解比较粗浅,用途上 access token 是给一个相对较短有效期的授权,而 refresh token 则是用来续签的,有效期较长,给受信任的客户端环境才签发。在 access token 有效期内无需重新登录,在 refresh token 有效期内无感续签,比如本次登录没勾选保持登录状态,access token 可在本次会话中一直使用只要你别关闭浏览器,关闭标签页重新开个网页依旧是登录状态的;如果登录时勾选了保持登录状态,那么 refresh token 应该是持久化保存的,重开浏览器什么的依旧可以维持登录状态,因为你的客户端可以拿 refresh token 去重新签一个 access token 。而超过 refresh token 有效期了则强制要求登录一次验证身份,这是一种很简单的安全手段。至于数据库存不存查不查那实际上是看会话管理上需不需要,实际上可以不要的
|
42
realpg PRO 我给你举个不恰当的方便理解的例子.
有一个系统, 他的安全等级较高, 采用了天顶星科技都无法破解的加解密系统存储用户名, 采用了天顶星科技的都无法创建碰撞的 hash 算法存储密码 一次加解密用户名开销要 30 秒, 一次 hash 开销要 5 秒 这时候,不用 refresh token 和用 refresh token 的性能差异就非常明显了... 然后这只是极端情况, 但是所需计算性能的维度因素是可以转换的 现实中你可能并没有这种加密要 30 秒的算法, 但是你可能有 10 亿活跃并发请求, 照样压死算法执行器 |
43
teric 1 天前
如果不用双 token,你准备让你的单 token 多久失效,如果你有多个系统需要鉴权,如果这时候要控制用户访问,这时候单 token 应该怎么做?
|
45
treblex 1 天前 via iPhone
像对接微信接口的时候,比较适合这种场景,服务器和服务器的交换
我也总觉得用户端不适用这种场景 |
46
Yuunie 1 天前
主要就是降低了服务器查 token 的开销,还有就是能存点公开信息放里面,后面也不用再查。
Access Token 里面存了用户信息,如果 Access Token 没过期就可以直接用里面的数据,Access Token 有过期时间,前端一般会在过期前几分钟的调用续签接口(通过 Refresh Token ),让后端签发 Access Token ,Refresh Token 是做了存储的,所以可以控制用户是否还能续签,从以前的每次调用都要查 Token 到现在一段时间后才查 Refresh Token ,降低了开销(一般续签接口还会做限制,防止频繁续签)。 问题就是 Access Token 有时效,不能马上过期,这是一个毛病 |
47
fun201108 1 天前 正在学习这个功能,基于现有了解,Access Token 放 storage ,允许 js 读写,Refresh Token 要放 cookie ,http only 不能 js 读取。
|
48
edcopclub 1 天前 via Android
提供服务 api 之类的做鉴权场景比较合适,两个 token 同时泄露的概率比较小,安全性要好一点。
|
49
iseki 1 天前
还有一个原因,刷新 token 和认证 token 未必是供同一方读取的。在一个职责完全分离的体系里,AS(认证服务器)和 RS(资源服务器)未必具有同样的安全基线,甚至未必是由同一实体控制。很显然,无限期有效的令牌必须不能被 UA(用户代理——客户端)和 AS 以外的第三者读取,否则角色就要混同了。
|
50
iseki 1 天前
举例这里粘贴一下《 OAuth 2.0 授权框架》中对角色的定义:
> resource owner > An entity capable of granting access to a protected resource. When the resource owner is a person, it is referred to as an end-user. > resource server > The server hosting the protected resources, capable of accepting and responding to protected resource requests using access tokens. > client > An application making protected resource requests on behalf of the resource owner and with its authorization. The term "client" does not imply any particular implementation characteristics (e.g., whether the application executes on a server, a desktop, or other devices). > authorization server > The server issuing access tokens to the client after successfully authenticating the resource owner and obtaining authorization. 抛开 RO 不谈,RS Client(UA) AS 是三个不同的角色,refresh token 是不应该提供给 RS 的 |
51
iseki 1 天前
另外就是,实践上,Refresh Token 也必须接受更严格的安全审计,甚至可能需要使用单棘轮之类的技巧来提高安全性
|
52
zuixinwenyue 1 天前
@fun201108 都是 httponly 有什么问题?
|
53
zuixinwenyue 1 天前
@edcopclub 两个 token 要泄露都会泄露
|
54
LeegoYih 1 天前
歪一个话题:
我这 JWT 已经退化成只简单包装一个用户 ID ,解密后通过用户 ID 再去 Redis 查 Session 。 这样做的目的是为了实现多设备同时登录,以及踢下线功能。 很多人觉得这样的话 JWT 都没有必要用了,直接用 UUID 代替 Token 就行,其实仔细想想 JWT 这么用是合理的: 1.若用户 ID 是敏感数据,那直接暴露在客户端是不安全的,通过 JWT 包装避免泄露; 2.若 JWT 过期,那认为 Redis 的 Session 也过期了; 3.若 JWT 是伪造的,那验签不会通过,也不会访问 Redis ,防止恶意攻击。 |
55
sunorg 1 天前 via Android
jwt 和 restful 一样,属于过度设计。access token 生命周期内没法废掉这个 token 的设计本身就是 bug. 后期要改进,比如放内存,放 redis. 再改验签算法。
这种行为跟以前自己维护一个 token 没啥两样,纯粹脱%裤子放 p. |
58
ninjashixuan 1 天前 @LeegoYih jwt payload 只是简单 base64 而已,不存在避免泄露吧。
|
59
DeWjjj PRO openresty 做运维的可能用的多,一般后端应该不太聊这个。
双 token 应该是用来分流,在线控制用户。 |
60
laikicka 1 天前
@LeegoYih 问题 jwt 不是加密啊.. header 和 payload 都只是 Base64URL 编码的 JSON ,任何拿到 token 的人都能还原出里面的内容
|
61
kuanat 1 天前
在讨论安全之前,要先定义什么是安全,或者说要应对的威胁模型是什么。
- 如果是 token 伪造,那 session (也就是你说的 token+redis )和 JWT (双 token )没区别,都是后端签发的。 - 如果说是身份冒用,两者也没区别,只要持有合法 token 就视作有效。 - 如果指的是 token 撤销,那么 session 比 jwt 好一点,因为它可以实时撤销,而 jwt 只能等它过期。 “性能也不见得差”这句话有毛病。session 方案的逻辑是有个中心化的实时鉴权后端,要负责对所有业务请求进行身份认证。现实里这个单点是极其脆弱的,水平扩展能力也非常有限。 由此诞生的 JWT 之类的方案,并不是要做得比 session 更安全,而是要解决 session 方案的性能瓶颈。 准确来说,解决性能瓶颈靠的是通过无状态 AccessToken ,将鉴权转移到每个业务单元,业务单元只需要解码而不需要实时后端查询。 为了让 JWT 方案也能达到和 session 方案一样的安全水平,那就要将 AccessToken 的有效期设定得越短越好。 但是 JWT 方案是无状态的,如果要获得新的 AccessToken 是无法像 session 一样自动更新的,必须要走一遍完整的登录验证过程。 所以就有了 RefreshToken ,它解决的是方便获得短时效 AccessToken 的问题。这个“双”token 的重点是方便。 PS 稍微补充一点:如果是 web 应用场景,RefreshToken 多数存储于 HttpOnly/Secure/SameSite=Strict cookies 中,防止 js 读取,也避免 XSS 攻击(因为即便后端被注入恶意代码,这个代码被当前用户执行后也无法获得 cookie 内容)。AccessToken 存储于内存变量中,通过 js 代码以 header 的形式传递,这样可以防止 csrf 攻击(因为跨域的时候不可能带上这个 header )。 |
62
lllllliu 19 小时 44 分钟前
不管什么类型的 Token/Session/Idf.只要是泄漏了都不安全,其他单/双看业务场景。比如你仍可以使用单/双 Token 时,再去对敏感接口进行一次性令牌的发放和授权。
|
64
mengpp 18 小时 43 分钟前
@photon006 这是业务设计问题了,单 token 也能做续签,在 jwt 里的时间是 token 过期时间,后端校验逻辑增加一个允许重签的周期,比如 token 签发的过期时间是 2 小时,允许重签是 8 小时,当 jwt 校验发现过期时,满足重签签时间就直接重签,就续上了,不需要登录
|
65
wecgwm1998yichen 18 小时 30 分钟前
双 token 有两个过期时间,单 token 不如不用 jwt
|
66
LeegoYih 17 小时 25 分钟前
@ninjashixuan #58 我的问题,没说清楚,我用的是 JWE
|
67
photon006 17 小时 22 分钟前
@mengpp accessToken 快过期 ≈ 已不可信
如果: 过期还能换新 → 那“过期”就失去意义,还不如签发一个长期 token 折腾续签干嘛 没过期才能换 → 那你没解决任何问题 这是一个逻辑自洽但安全破产的设计。 在用户“不参与登录”的情况下,重新获得一个新的 accessToken 而这件事在鉴权模型里意味着: 你必须有一个“比 accessToken 权限更高或生命周期更长”的凭证 这正是 refreshToken 的角色。 |
68
ihmily 16 小时 23 分钟前
问题 1:
单 Token 方案:同一个 token 既用于访问又用于刷新 问题场景: 用户在 Tab A 刷新了 token ,得到 token_v2 用户在 Tab B 仍然持有 token_v1 Tab B 的请求会失败(因为 token_v1 已在黑名单),无法刷新 需要复杂的跨 Tab 同步机制 问题 2: 单 Access Token 的暴露场景: 每个 API 请求的 HTTP Header 中 浏览器开发者工具的 Network 面板 可能被记录在服务器日志中 可能通过中间代理服务器 如果有 XSS 漏洞,容易被窃取 假设你每天发送 1000 个请求 → Access Token 暴露了 1000 次,用作刷新 token 不安全 而双 token 中 Refresh Token 仅在以下情况使用: ✅ Access Token 过期时(比如每 8 小时一次) ✅ 只发送到特定的刷新接口 ✅ 不会出现在普通业务请求中 虽然 Refresh Token 也有被窃取的风险,但是风险小很多 |
69
ihmily 16 小时 0 分钟前
另外, 双 token 比单 Token 也有利于日志分析:
检测到 access_token 异常 → 可能是网络攻击 检测到 refresh_token 异常 → 可能是账户被盗 场景 A:Access Token 被重复使用, 重放攻击 时间线: T0: 用户请求 GET /workflows ,Access Token 在网络中传输 T1: 攻击者在网络中拦截到这个 Access Token T2: 攻击者立即用这个 Access Token 发起请求 T3: 15 分钟内,Access Token 仍然有效 → 攻击成功 # 日志中看到: - 同一个 Access Token 来自不同 IP - 同一个 Access Token 在短时间内高频使用 - User-Agent 不一致 影响范围: 相对局部(只影响当前 token 时间窗口) # 场景 B:Refresh Token 被重复使用 时间线: T0: 用户登录,得到 RT_1 ,存储在 localStorage T1: 攻击者通过某种方式窃取了 RT_1 (钓鱼、数据库泄露、恶意软件等) T2: 用户的浏览器自动刷新,用 RT_1 → 得到 RT_2 ,RT_1 进黑名单 T3: 攻击者尝试用 RT_1 刷新 → ❌ 触发第 133-135 行的检测 而如果是单 token ,则无法区分是哪种场景导致的黑名单 Token 被重复使用 单 Token 重复使用的多种可能性. 有可能是 1.并发刷新(正常行为) 用户打开页面,5 个 API 同时发起: ────────────────────────────────────── T0: 5 个请求都带着过期的 token_v1 T1: 5 个请求都返回 401 T2: 5 个响应拦截器同时触发刷新 - 请求 1: POST /refresh { token: token_v1 } → 成功,返回 token_v2 ,token_v1 进黑名单 - 请求 2: POST /refresh { token: token_v1 } → ❌ 黑名单检测触发 - 请求 3-10: 同样被拒绝 2.多 Tab/多窗口(正常行为) 用户同时打开多个 Tab: ────────────────────────────────────── Tab A: 用户正在浏览,token 刚好过期 Tab B: 用户也在操作,同一个 token 过期 Tab A 先刷新: POST /refresh { token: token_v1 } → 成功,token_v1 进黑名单 localStorage.setItem('token', token_v2) Tab B 延迟几秒刷新(还没来得及读取新 token ): POST /refresh { token: token_v1 } → ❌ 黑名单检测触发 # 后端日志: # 以上问题检测到 token_v1 被重复使用,但不能确定是不是网络攻击! 3.账户被盗(异常行为 真正的攻击场景: ────────────────────────────────────── T0: 攻击者窃取了 token_v1 T1: 合法用户刷新:POST /refresh { token: token_v1 } → token_v2 ,token_v1 进黑名单 T2: 攻击者尝试刷新:POST /refresh { token: token_v1 } → ❌ 黑名单检测触发 # 后端日志: # 检测到 token_v1 被重复使用 # 这次是真的攻击! |
70
mengpp 14 小时 34 分钟前
@photon006 #67 你在说单 token 的用户体验问题,我也在回答单 token 的体验问题,重签过程本身也应存在安全策略,不认可《 accessToken 快过期 ≈ 已不可信》这个结论,将重签时机定义在原本的 token 过期时间内就好了
|
71
aloxaf 13 小时 55 分钟前
我认为这套玩意儿最适合大厂,access token 无状态的特性可以让一些简单但高频访问的服务也变成无状态的,方便横向扩展(比如资源服务器)。这类服务对安全性也没有很高要求,所以 token 没有及时 revoke 也无所谓。
|
72
hatch 13 小时 30 分钟前
jwt 本身设计就是"无状态",意味颁发后在令牌 ttl 内会被一直允许访问。
refresh token 的存在是为了再次检验用户是否允许被授权。 至于安全性,除了降低令牌 ttl ,其它种做法似乎都是将 jwt 变成"有状态",当然你既然选择了 jwt ,那就要接受它的优缺点。 |
73
fun201108 13 小时 0 分钟前
@zuixinwenyue #52 都是 httponly ,授权就都只能交给后端处理,js 无法读取呀
|
74
server 12 小时 54 分钟前
什么 Access Token 和 Refresh Token 单纯个人看法 一直觉得这玩意就是 脑袋一热
|
75
datadump 11 小时 53 分钟前
|
76
photon006 11 小时 12 分钟前
@mengpp 用户体验是可以通过双 token 续签解决的,比如在每天页面加载时尝试续签,满足条件且快过期了就续签新 token ,根本不会遇到上一秒还在填表下一秒直接过期的问题,而续签的核心在于不能用自身一个快过期的 token 换新,这其实相当于没有有效期,你的程序能无限使用攻击者也可以。
|
77
scrange 6 小时 33 分钟前
要回答这个问题便绕不开 OAuth2.0 和 OIDC (上述两者是较为庞大的话题就不过多引入了)。这里先阐明一个前提:OAuth2.0 ( RFC 6749 )中规范的双 token 是用在授权场景的并没有提到过任何相关认证的话题。而我们通常意义上见到的双 token 认证个人认为是从 OAuth2.0 协议中演化出来的一个变种(实际上 Cookie+Session 能很好的完成安全认证的相关流程,RFC 6896 提供了一系列的措施来补充整个流程的安全漏洞,为啥不用呢),网上很多文章充斥的都是方便跨域,更安全,扩展性强等话题来吹捧 JWT Token 认证方式,但我们试想下整个使用 JWT 认证(或其他什么 token)流程,就会发现,为了达到 Cookie+Session 的效果不得不去做些违背 JWT Token 设计之初的原意(把 Token 缓存起来)(扯远了)。单 JWT Token 配合缓存确实能达到认证的效果,但存在泄露的可能,我们不能签发一个很长时间的 JWT token 这会增加泄露时的风险,引入 Refresh Token 后那么每次刷新的时候可以同时换取新的 Access Token + Refresh Token 产生新的后旧的便会失效,而且刷新的时候可以做一些审计(判断上次的访问地址,频次等推断是否是合法访问)从而拒绝并提示用户登录或者换出新的 JWT token ,双 token 即使泄露顶多换取用户一次重新登录,而单 token 的话由于 JWT 的自包含性在签发时间内都是有效的无法快速的撤销其授权,会让其在泄露之后长时间有效。事实上 OAuth 2.0 协议中对于 Public Client (浏览器端的单页应用等)并没有强制签发双 Token ,基于 Cookie+Session 配合 OIDC 协议中的 prompt=none 策略,也可以无感的换取新的 token 。并且 OAuth2.0 中提供了 Token Introspection 端点和 Token Revocation 端点用来主动撤销 Token 防止泄露或用户主动中断授权后避免三方系统继续持有有效的访问凭据。回答有些简要,希望不会因为引入的一些拗口话题造成困惑~
|