V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
cc959798
V2EX  ›  Java

请问 OAuth 中的 access_token 为什么需要过期

  •  
  •   cc959798 · 2018-06-12 16:08:00 +08:00 · 9495 次点击
    这是一个创建于 2117 天前的主题,其中的信息可能已经有所发展或是发生改变。

    为什么需要设置国企 refresh_token 来刷新 access_token,有些人说是因为 Access_token 会过期,refresh_token 也会过期,为什么不设计成 access_token 和 refresh_token 一样长的过期时间,然后 refresh_token 就不需要了,反正 refresh_token 也会过期

    52 条回复    2020-05-29 18:14:54 +08:00
    Rekkles
        1
    Rekkles  
       2018-06-12 17:08:34 +08:00
    refresh_token 过期时间比 access_token 要长,这样 access_token 即使过期了,也可以用 refresh_token 去重新刷新 token,既为了安全考虑,也为用户体验着想
    littleylv
        2
    littleylv  
       2018-06-12 17:12:41 +08:00
    如果只是 access_token 过期了,可以继续用 refresh_token 来换取 access_token,换取的过程直接调接口,用户感觉不出来。
    一旦 refresh_token 过期,就需要用户重新登录、授权等流程了。

    所以 refresh_token 的作用可以理解成,不需要每次 token 过期就需要用户登录授权。
    你说的“ refresh_token 就不需要了”完全是不对的
    march1993
        3
    march1993  
       2018-06-12 17:20:23 +08:00 via iPhone
    我和你有同样的疑问,我觉得 access_token 也没有意义。从安全角度讲,拿到 access_token 离拿到 refresh_token 也只有一步之遥了
    cc959798
        4
    cc959798  
    OP
       2018-06-12 18:08:11 +08:00
    @march1993 网上的那些资料只讲了怎么做,但是至于为什么没说清楚哦,我相信很多人是有疑问的
    cc959798
        5
    cc959798  
    OP
       2018-06-12 18:10:30 +08:00
    @littleylv 你好,refresh_token 作作用我清楚,不需要重新登录就可以再次拿到授权,但是如果把 access_token 的过期时间和 refresh_token 一样长的话感觉就不需要 了,毕竟如果一样长的话,access_token 过期了 refresh_token 也过期了,然后重新登录不就行了

    至于安全方面我不太明白 refresh_token 的存在的意义
    zhouyou457
        6
    zhouyou457  
       2018-06-12 18:21:46 +08:00
    refresh_token 是一次性的,同时还需要校验客户端的有效性,比如客户端 secret_key 之类的
    zhouyou457
        7
    zhouyou457  
       2018-06-12 18:23:53 +08:00
    在我做的系统中 access_token 过期时间是 1 天,而 refresh_token 过期时间是一个月...如果按你说两者同时过期,让用户输入密码的话,使用体验是很差的....至少我不愿意在一个应用中反复输入密码
    littleylv
        8
    littleylv  
       2018-06-12 18:41:24 +08:00   ❤️ 1
    @zhouyou457 #7
    也许楼主的意思是:如果他不需要 refresh,然后把 access 设置成很久(比如和你的 refresh 一样一个月),那是不是也是一个月后再让用户登录授权,跟你的系统没两样(看起来没两样)。

    但是为了防止 access token 的泄露,一般会把他设置很短时间比如一天。


    @march1993 #3
    拿到 access 不等于可以拿到 refresh,因为 access 会经常在 api 调用中传输,会有安全隐患,但即使被人拿到了,别人根本不知道 refresh,所以只要几个小时后 access 失效,别人也就没辙了。

    这就是为什么需要两者并用,切 access 时间很短的原因了把
    lurenw
        9
    lurenw  
       2018-06-12 18:57:49 +08:00   ❤️ 1
    access_token 暴露在外面的时间越久越危险,需要不断变化来防止泄露。

    refresh_token 用专门的接口和单独的服务器,达到相对的 safer。

    ps. oauth 和 jwt 那套标准和流程真的啰嗦。
    mooncakejs
        10
    mooncakejs  
       2018-06-12 18:59:10 +08:00
    refresh_token 的获得和更换 access token 只有 2 个接口,这两个接口需要严格的安全措施( https 等),但是对于 access_token 的使用,没有这个限制,所以泄露风险大大增加。
    maichael
        11
    maichael  
       2018-06-12 19:07:46 +08:00   ❤️ 1
    There is a security reason, the refresh_token is only ever exchanged with authorization server whereas the access_token is exchanged with resource servers. This mitigates the risk of a long-lived access_token leaking in the "an access token good for an hour, with a refresh token good for a year or good-till-revoked" vs "an access token good-till-revoked without a refresh token."
    maichael
        12
    maichael  
       2018-06-12 19:10:16 +08:00
    上面忘记加引用了。

    大体意思和 #9 差不多。
    march1993
        13
    march1993  
       2018-06-12 19:51:58 +08:00 via iPhone
    @littleylv 那完全可以授权多个 access_token,独立审计,也比这种短时 access_token 好啊
    Foolt
        14
    Foolt  
       2018-06-12 20:13:41 +08:00
    @march1993 你觉得拿到 access_token 离拿到 refresh_token 也只有一步之遥,是因为你的业务场景比较简单,access_token 和 refresh_token 保存在同一个地方。

    有的场景并不是这样。比如说你要开发个 Javascript 版微博,用户授权后,你直接在浏览器用 JS 获取微博内容,那么 access_token 就会暴露在浏览器之中,但 refresh_token 只在你的服务器里,当用户退出网页后你可以通过刷新令已经暴露的令牌失效。
    sidgwick
        15
    sidgwick  
       2018-06-12 20:19:03 +08:00 via iPhone
    @littleylv 我也觉得是这样,access token 需要经常在网络上传输。这传来穿去的就不安全了
    march1993
        16
    march1993  
       2018-06-12 21:40:50 +08:00   ❤️ 1
    @Foolt 这个客户端应该是个第三方 JS 微博客户端对吧?这个短时 access_token 在用户每次登陆时都需要去刷新吧,存不存 refresh_token 一样啊,要 revoke 也可以直接用这个 access_token。所以存这个 refresh_token 的意义在哪里…要安全完全可以隔离不同的 token。客户端如果不安全,拿到了 access_token,那离拿鉴权也不远啊… 所以我不能信服你这个说法
    march1993
        17
    march1993  
       2018-06-12 21:44:07 +08:00
    当然我觉得拿鉴权还是有点过了,不过如果可以拿到 access_token 一次,就说明可以不断地拿了吧,只要用户经常使用的话?
    chinvo
        18
    chinvo  
       2018-06-12 21:46:03 +08:00 via iPhone
    @march1993 #16 此言差矣

    refresh token 必须和 client secret 一起用才有效

    而且在权限限制严格的情况下,refresh token 必须在满足特定条件下才会被发放给 oauth client

    而 access token 是经常暴露出来的,并且可以先送给第三方 resource provuder,但 refresh token 只能在 oauth client 和 authentication provider 之间传递并且必须被保密存放
    chinvo
        19
    chinvo  
       2018-06-12 21:51:29 +08:00
    @march1993 #16

    另外 agent 不等同于 client,agent 是暴露给用户的部分,包括浏览器、app,而 client 是指包含 agent 和执行 code 换 token 或者 refresh token 换 token 的服务器端两部分,单纯的 agent 形式的 client 又叫 public client,是不能使用 client secret 和 refresh token 的

    #17 但是非法的 agent 能偷到一次 access token 不代表可以偷到第二次,而如果能偷到 refresh token 并使 refresh token 有效,就是非常严重的安全事故了
    march1993
        20
    march1993  
       2018-06-12 21:51:47 +08:00
    @chinvo 我觉得这种做法看似加强了安全,实则让审计成了一个黑箱。在若干第三方 resource provider 中,设有一个被入侵污染了,如何发现并清除呢?由于 access_token 是公用的,我任务这种情况下就很麻烦。
    chinvo
        21
    chinvo  
       2018-06-12 21:52:41 +08:00
    feng huang 的 V2EX iOS app 里面误点感谢突然不能取消感谢好尴尬……
    chinvo
        22
    chinvo  
       2018-06-12 21:54:15 +08:00
    @march1993 #20 所以 access token 有效期是短暂的,即使泄露不会造成太大危害,但是如果按你的思路设置为长期,就是很危险的了,尤其是有一些 authentication provider 不支持 revoke access token 的情况下
    march1993
        23
    march1993  
       2018-06-12 21:56:49 +08:00
    @chinvo 不啊,按照我的思路,我的 token 是独立的,也就是这个 token 能做的事情也是有限的,所以危害是可以控制的。在被污染的 provider 被发现之前,它也可以一直请求更新 token,所以我觉得这个危险可能更严重。
    march1993
        24
    march1993  
       2018-06-12 21:57:48 +08:00
    @chinvo 即便如此,像我们这种下游开发者也只能跟着 access_token 走了
    chinvo
        25
    chinvo  
       2018-06-12 21:58:57 +08:00
    @march1993 #20 抱歉认错了,误认为你是楼主……

    access token 被泄漏的时候的安全性保障,来自于短期有效。

    另外为了避免 public 的 client (单纯 agent 的 client,包括网页、手机 app )所取得的 access token 泄漏造成麻烦,还引入了 PKCE
    chinvo
        26
    chinvo  
       2018-06-12 21:59:50 +08:00
    @march1993 #23 resource provider 并不能更新 token,他只能使用 token 去进行认证或者访问 api,只有 client 能更新 token
    march1993
        27
    march1993  
       2018-06-12 22:05:32 +08:00
    @chinvo 我理解的短时对于入侵者来说用 access_token 配合预先编写的程序可以干一堆事情了,所以可能我理解上有偏差
    chinvo
        28
    chinvo  
       2018-06-12 22:16:15 +08:00   ❤️ 1
    @march1993 #27 resource provider 的接入一般是受 authentication provider 管理方的严格限制的,所以这个角度不容易泄漏。

    大部分只在服务器上调用 RP 接口的 client 也不会泄漏 token。

    那么就只剩下 agent 了,而 agent 是不允许持有 client secret 和 refresh token 的。

    此时 access token 若泄漏,只会造成短时间的风险(一般是 3600 秒),虽然可以做一堆事,但远比直接泄漏用户密码或者长期令牌要安全的多。

    更严格的策略要求 agent 也不可以持有 access token,必须通过后端服务器与 IdP/RP 交互。

    在最严格策略下,可能的泄漏风险是换取 access token 之前,authentication provider 返回的 code,引入 PKCE 对 agent 进行 challenge,code 与 PKCE 的 code_verifier 绑定,只有此 agent 的后端服务器可以用 client_secret, code_verifier 和 code 换到 access token。
    SingeeKing
        29
    SingeeKing  
       2018-06-12 22:17:51 +08:00
    假设 access token 一天过期一次

    那么 refresh token 换取 access token 每 24h 只要一次就好了,也就是说每天只有这一次的机会会泄漏 refresh token
    而 access token 则会在每一次调用中都可能泄漏,泄漏几率远大于 refresh token


    ---------------

    其实问题来了,如果服务器是 https 的话,那么如果不考虑中间人应该都不会泄漏,而如果被中间人了那么很大几率 refresh token 也保不住(毕竟被中间人攻击的话手机或电脑应该已经被安装了第三方根证书)
    chinvo
        30
    chinvo  
       2018-06-12 22:22:32 +08:00   ❤️ 1
    @march1993 另外你 #24 说的没错,通常情况下,token 泄漏,client 的开发者是除用户之外最大的受害者。

    所以理论上 client 的开发者有权利和义务选择最严格的流程并且完整实践 OAuth 2.0/OpenId Connect 所有对于安全性的要求和建议。

    而对于敏感数据的提供方,作为 RP 应当要求 client 和 IdP 使用严格的 token 交换机制。
    作为 IdP,因其本身不提供敏感数据( OAuth 中只作为用户身份认证令牌的提供方,OpenId Connect 中还要提供一个 Userinfo Endpoint ),则应当为 RP 和 client 的安全性考虑,为他们实作标准中提出的安全机制。
    chinvo
        31
    chinvo  
       2018-06-12 22:24:17 +08:00
    @SingeeKing #29 按照 IETF 和 OpenId 的要求,refresh token 和 client secret 是不可以放在 agent 上的,也就是说,其实目前大部分将 refresh token 和 client secret 保存在用户手机或者其他设备的 agent 是不合规且有隐患的。
    SingeeKing
        32
    SingeeKing  
       2018-06-12 22:25:27 +08:00
    @chinvo #31 What。。Refresh token 不放在客户端怎么刷新。。
    chinvo
        33
    chinvo  
       2018-06-12 22:26:45 +08:00
    @SingeeKing #32 由客户端的服务器刷新。

    如果你真的在客户端能成功刷新 access token,那么你的 client secret 已经至少暴漏给用户了
    choury
        34
    choury  
       2018-06-12 22:26:47 +08:00
    @SingeeKing #29 access token 可以放在 url 里面的,能拿到这个的可能太多了,而 refresh token 只存在自己服务器上,除了和 auth server 交互之外不会被传送
    说白了这套流程防的是不怀好意的第三方,并不是用来防开发者的
    choury
        35
    choury  
       2018-06-12 22:28:20 +08:00
    @SingeeKing #32 放在客户端,那客户就可以伪造你了……
    ooh
        36
    ooh  
       2018-06-12 22:30:49 +08:00
    cookie 为什么需要过期?
    q397064399
        37
    q397064399  
       2018-06-12 22:56:52 +08:00
    本身并没有什么卵用,

    通信层面上保证安全的是 https 跟非对称加密协议,
    客户端层面上是开发者 保证内存不被恶意 dump,token 不被恶意获取

    客户端如果保护不了 token 那也同样保护不了 refresh_token
    非对称加密要是 证书被恶意篡改 遭受中间人攻击 同样是被脱了裤子,
    你捂住了下面,就捂不住上面,也是没有什么卵用

    另外 md5 挑战认证,了解一下?
    chinvo
        38
    chinvo  
       2018-06-12 22:59:22 +08:00
    @q397064399 #37 所以 refresh token 是禁止放在 agent 的
    q397064399
        39
    q397064399  
       2018-06-12 23:02:23 +08:00
    @chinvo #38

    不解,如果 refresh_token 不放在客户端,客户端如何刷新 token,
    需要借助服务器来刷新么? 那服务器 与 客户端 怎么确认 认证身份?
    chinvo
        40
    chinvo  
       2018-06-12 23:05:01 +08:00
    @q397064399 对的,要用服务器来刷新,客户端和服务器之间没有具体规定,你可以用 access token (由 IdP 颁发而非自行颁发)、cookie、session、或者自行颁发 access token
    q397064399
        41
    q397064399  
       2018-06-12 23:10:30 +08:00
    @chinvo #40

    如果刷新 token,还要另外再弄一套认证鉴权机制
    我觉得意义就不是很大了,token 跟 refresh_token 的存在
    本身就是因为穿了加密协议这条内裤, 假如客户端自己不能保护好 token 跟 refresh_token
    那其它的鉴权机制 也无法保证 用户的认证信息


    之前 Linus 邮件里面 就批评了那些安全专家, 我觉得 Linus 的观点很正确,
    安全的重点从来是人,而不是程序机制,任何机制都无法避免 看守金库的老大爷喝醉之后被小姐骗走钥匙
    march1993
        42
    march1993  
       2018-06-12 23:27:35 +08:00
    @chinvo 我觉得如果你提 IdP 和 SP 的话属于另外一个范畴了,IdP 和 access_token、refresh_token 解决的是两个不同的问题吧?
    chinvo
        43
    chinvo  
       2018-06-12 23:28:44 +08:00
    @march1993 呃,access_token 和 refresh_token 就是 IdP 发给你( client )的啊
    Foolt
        44
    Foolt  
       2018-06-13 00:29:24 +08:00 via Android
    @march1993

    如果只有访问令牌,刷新直接用访问令牌,这意味着用户的访问令牌一旦泄露,黑客可以立即用访问令牌刷新令牌,令你服务器的访问令牌失效,你再想刷新你都刷新不了。这时黑客就可以一直使用访问令牌,直到用户取消授权或者刷新授权。

    刷新令牌就是解决这个问题的,刷新令牌长期有效,访问令牌短期有效,就算用户泄露了访问令牌,你服务器也可以通过刷新令其失效,退一步讲,即使没刷新,最多几个小时(一般是一两个小时)就失效了。不会出现用访问令牌刷新,一旦泄露黑客就取代你的情况。
    icz
        45
    icz  
       2018-06-13 08:12:05 +08:00 via iPhone
    @chinvo 这么说我怎么觉得 refresh token 放在 agent 上更安全? refresh token 只要不配合 client secret 就是无效的,而 refresh token 相当于是一个临时的用户密码,这样不就相当于在客户端的服务器上明文存用户密码了..?客户端服务器如果被攻破 client secret 和 refresh token 就会一起泄漏。如果 refresh token 放在 agent 上,client 接收 agent 的刷新请求(并用自己的手段认证 agent )再向 oauth 认证服务器请求会不会更好一些?
    catinred
        46
    catinred  
       2018-06-13 11:13:59 +08:00
    要分两种情况来讨论,不要混淆在一起。1.通讯线路被黑,例如 MITM。2.客户端被破解。
    CoderGeek
        47
    CoderGeek  
       2018-06-13 16:03:51 +08:00
    refresh_token 未过期 直接申请新的 access_token
    refresh_token 过期 重新登录获取授权的 access_token 和 refresh_token
    CoderGeek
        48
    CoderGeek  
       2018-06-13 16:06:57 +08:00
    你要是觉得 OAuth 麻烦 可以用 JWT 简单 或者看看 Apache OAuth2.0 的介绍上面有流程
    https://tools.ietf.org/html/rfc6749#section-1.5
    CoderGeek
        49
    CoderGeek  
       2018-06-13 16:09:03 +08:00
    如果你自己做个开放平台 类似微博 微信 百度 豆瓣 他们都是这样的流程 = = 看他们 授权介绍 ...虽然有的实现很乱
    但基本都是按照 OAuth2.0 来的
    mingyun
        50
    mingyun  
       2018-12-18 22:10:44 +08:00
    JacobAngle
        51
    JacobAngle  
       2019-12-03 14:20:37 +08:00
    我还是不理解 refresh_token 怎么用才会安全? refresh 请求另一个接口来获取 access_token,那么别人知道 refresh_token 了也就很容易获取到 access_token 了呀?难道是以为别人不知道 refresh_token 的接口?通过分析是很明显就会知道的呀。所以 refresh_token 到底是怎么个安全呢?只是避免在网络传输中被截获?那直接 https 是不是就不会被截获了?那还要 refresh_token 有何用?很迷惑~!
    lubberland666
        52
    lubberland666  
       2020-05-29 18:14:54 +08:00
    fuck 深感同意 @JacobAngle 上面有同学说 refresh_token 放在服务端 刷新的时候 需要另外一套鉴权机制来保证刷新过程, 如果一套鉴权机制 需要另外一套鉴权机制来保证安全,那感觉没啥太大意义了
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2836 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 31ms · UTC 12:56 · PVG 20:56 · LAX 05:56 · JFK 08:56
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.