关于 token 过期的疑惑,为什么需要 refresh token?

2021-12-08 18:00:08 +08:00
 nianyu

平时做项目早就习惯了,在拦截器中将 access token 放入 request header 头中,如果 token 过期,则请求 refresh token 接口,拿到一个新 token ( babalabala ,还有很多细节 isRereshing and 刷新过程中将新请求的 request 放入队列...)

但是一直不是很明白为什么需要 refresh token

疑问 1: 为什么不能将 token 设置的有效期长一些,失效就直接重新登陆,而需要不停的刷新 token, 毕竟 refresh token 过期的时候,总还是要重新登陆的。

在网上搜了相关问答,有人说用户不能正在进行操作时,突然因为 token 过期重新登陆了了,然而当 refresh 也过期的时候,依然要重新登陆。

疑问 2: 有人说是为了安全问题,如果 token 被人劫持,就可以冒充用户进行一些操作,所以需要将 token 的有效期设置的非常短,这样即使破译了 token ,没过几分钟就失效了,我觉得没有道理啊,客户端通常将 access token 喝 refresh token 存在 storage 中,或者说既然能拿到 token 为什么拿不到 access token 。

12138 次点击
所在节点    信息安全
42 条回复
Qsong
2021-12-09 10:14:11 +08:00
token 的过期时间一般会比 refeshToken 的过期时间短很多,保证 token 被盗取后无法持久的做坏事。
refeshToken 一般会存储在后端服务器,而不会放在客户端,如果说放在客户端,那 token 将毫无意义
当 token 过期后,后端会利用 refeshToken 返回一个新的 token 给到前端使用,而不是前端拿一个过期的 token 获取一个新的 token ,只要 token 过期了,那么 token 就已经是无效的了,只能用新的 token 才可以正常使用。
一般后端会将 token 放在请求头里返回给前端,前端只要拿着 header 里的 token 调用接口就行了,对于是否刷新了 token 也是无感的
dingwen07
2021-12-09 10:15:39 +08:00
如果用户持续地访问这个网站,他们可以一直保持登录状态,而不需要定期重新登录。
robinlovemaggie
2021-12-09 10:15:54 +08:00
token 的设计本身不负责安全性,所以劫持问题不应在 token 这里讨论。
aboat365
2021-12-09 10:16:03 +08:00
token 翻译成中文就是令牌。因为 HTTP1.1 协议每次请求都是独立的,不能复用的连接。所以,在每次请求中都需要带上令牌。令牌有效期越长,那么请求携带次数就越多,传输过程越容易暴露令牌,导致安全性下降。总而言之,就是一个令牌使用时间和次数越多,那么在使用过程中越不安全。反之,把令牌有效期设置的越短,那么就越安全。但如果这样子,将导致用户体验很差。那么如何解决这个矛盾的?对于经典的 web 应用,令牌的有效时间是 30 分钟,在有效期内使用令牌请求,后端将刷新令牌的有效期。如果超过 30 分钟再发起请求,服务端会要求前端带上 refresh token ,即刷新令牌。刷新令牌有效期可以设置很多天,比如设置一周。刷新令牌设置这么长时间那不是很不安全?其实不是的,刷新令牌相比前面每次请求使用的令牌来说,区别在于低频次使用。虽然有效期长得多,但使用次数非常低,有的方案只用一次。如前所述,使用刷新令牌换取普通令牌,并获取一个新的刷新令牌,原刷新令牌作废。如此,便实现了用户登录后,只要不超过一周内访问服务,那便可以一直免登录(例如你手机上的微信)。最后关于令牌本身,可以是服务端随机生成的 session id ,也可以是服务端不保存映射关系的 JWT ,主要看具体应用场景。

最后归纳一下,token 和 refresh token 的区别在于有效期一个短一个长。使用上 token 用于每次请求,refresh token 用于 token 过期后去换取新的 token 和 refresh token 。这样设计的目的,就是为了解决安全性和使用体验之间的矛盾。
libook
2021-12-09 10:29:41 +08:00
从需求出发:
1. 用户不希望做每个操作都进行登录验证操作,所以需要让用户会话有一定的有效时间;
2. 用户不希望在长期不做操作的情况下,比如离开电脑前,甚至电脑交给他人使用的时候,会话仍然有效,以至于可以被他人操作,所以用户会话的有效时间不能太长;
3. 用户不希望自己正在使用的时候会话突然过期,所以需要在用户会话过期之前,如果用户还有操作的话,就对会话续期(刷新)。

题主疑问 2 里面说的“有人说”的观点是错误的,安全性都是相对的,没有网络通信安全和客户端安全作为保障,token 机制不管怎么用都是无法保证安全的。
onhao
2021-12-09 10:40:19 +08:00
我只说我们的 refresh token ,这个接口就是起到延期 token 的作用,可以让用户能在一定的日期内登录始终是有效的,这样避免了 token 一直固定也可提升用户体验-无感登录
Rocketer
2021-12-09 11:11:16 +08:00
@VeryZero refresh token 每次使用都要校验状态。

至于什么时候拿 refresh token 去换取一个新的 access token ,那是客户端的事。它可以在 access token 即将到期时主动更新,也可以在服务端返回失效错误后再去更新,还可以在任何自己认为需要的时候去更新(比如自己刚修改了密码,于是立刻去获取个新的 access token )
neetrorschach
2021-12-09 14:05:58 +08:00
说下我在某外企客户那儿对接他们的 oauth2 的开发指导文档吧。
用户每次登录会获取 access token 和 refresh token
前端保存 access token 和 refresh token
每次前端请求带上 access token ,后端用 access token 去 oauth2 服务验证是否有效。
如果无效则反馈给前端,前端会再次用 refresh token 发送请求。oauth2 会验证 refresh token 是否在有效期内。如果有效,则返回新的 access token 和 refresh token (延长有效期)。前端更新存储的 token 。
如果 refresh token 无效则跳转到登录页。
refresh token 设置了一周时间。如果用户每天用,其实基本不会要求重登录。只有长期不用才会要求重新登录。
dinding
2021-12-09 14:43:01 +08:00
1 从权限上说,refresh token 是和授权服务器之间的凭证,access token 是和资源服务器之间的凭证。
2 从实现上,有效的 access token 可以有多个,但是 refresh token 只能有一个。所以前者可以实现为 self-contanined(包含了请求资源的所有信息),无需持久化存储;但后者必须存在某个地方。
3 从安全性上,为了防止泄漏,access token 一般不会有很长的有效期。这里,“泄漏”的方式,除了楼主说的 storage 外,还包括比如日志,非 https 的 cookie ,不可信的第三方等等。显然,经常使用的 access token, 要比不经常使用的 refresh token 泄漏的概率高。此外,refresh token 是要配合 client id/secret 一起使用的,通常 client id/secret 不会和 refresh token 存在一个地方。
whileFalse
2021-12-09 16:26:02 +08:00
为了把你踢下线。(服务器主动使登陆状态失效)
session 机制只要删除服务器 redis key 即可把你踢掉
token 机制中 access token 是离线验证的不走 redis ,所以用一个较短的寿命,等他过期了你拿着 refresh token 去续期的时候服务器不给你续,就是踢下线了。
AsherTan
2021-12-09 16:45:54 +08:00
1. AccessToken 和 RefreshToken 一般都是配合着使用,多用于第三方 openAPI 的鉴权,自己后端服务的登录鉴权的 token 一般不会弄个 RefreshToken 的。
2. AccessToken 和 RefreshToken 基于安全性考虑一般都是建议保存在服务端的,是由服务端去使用,不会在客户端直接使用 Access Token 的。
3. AccessToken 还是基于安全考虑,有效时间比较短,一般两小时。可以使用 RefreshToken 定时请求接口获取新的 AccessToken 。
Akesudia
2021-12-09 17:09:18 +08:00
1.Refresh Token 确实提高了安全性,短有效期就是防止 Access Token 被窃取后攻击者长期保持有效会话,如果使用了 Token 黑名单机制就无所谓了(但破坏了 stateless)
2.Access Token 在每个请求中附带,Refresh Token 只在 Access Token 失效时传输,被中间人窃取机会比 Access Token 小。
unco020511
2021-12-09 17:25:50 +08:00
@VeryZero #20 我还真没见过每次都携带 refresh token 的...
SheHuannn
2021-12-09 17:38:17 +08:00
大致看了上边的回复,access token + refresh token 的模式更多的是解决了 access token 续签的问题,对改进用户体验有帮助,好像在保证数据安全性方面没起到啥实质性作用。
ipwx
2021-12-09 17:41:40 +08:00
加密签名,可以验证 AccessToken 没有被篡改和捏造(解密出来“什么时候过期”,它就一定是正确的过期时间。客户端无法捏造这个时间)。那么每个后端服务器只要有一套解密的密钥就行了。

甚至集中的认证服务器,可以根据要访问的业务,调用不同的加密密钥去加密,这样的 Access Token 自然只有对应的业务才会承认。

这就是 Stateless 的核心 —— AccessToken 不用连接任何中央服务器,就能迅速检验它是合法的、不是捏造的。时间戳附带签名就能证明其真实性。
chi1st
2021-12-09 17:43:44 +08:00
求问 RefreshToken 到底应该放在哪里储存呢?
mrliusg
2021-12-09 19:57:48 +08:00
RFC6819 里详细解释了 OAuth 2.0 面临的威胁和应该做的安全设计。从整体上看就可以理解为什么要设计两个 Token ,且具有不同的特性。
dany813
2021-12-10 11:45:41 +08:00
RefreshToken 一般放在 redis 吗
daimubai
2021-12-10 22:32:35 +08:00
@Qsong 请教下,“当 token 过期后,后端会利用 refeshToken 返回一个新的 token 给到前端使用”,在什么时候返回呢。是后端返给前端 403 ,然后前端去调获取新 token 的接口拿到新的 token ,然后再二次重试上一次的请求吗
daimubai
2021-12-10 22:36:43 +08:00
@Qsong 因为这个时候 token 已经过期了嘛,怎么知道用户对应的哪个 refreshToken 啊

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/820927

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX