Authlib库存在一键账户接管漏洞:CVE-2025-68158深度解析

文章详细分析了Authlib库中存在的一个中危安全漏洞,该漏洞允许攻击者通过CSRF攻击实现一键账户接管。文中深入探讨了漏洞的技术原理、潜在影响、概念验证及修复建议。

Authlib 存在一键账户接管漏洞 · CVE-2025-68158

严重性:中等

发布时间: 2026年1月8日 更新于: 2026年1月9日 所属仓库: authlib/authlib

漏洞详情

受影响的版本: <= 1.6.5 已修复版本: 1.6.6

描述

Snyk 安全实验室团队在最近的研究项目中发现了影响Authlib库的安全问题。 我们识别出一个漏洞,可能导致使用Authlib库的应用程序发生一键账户接管。(CVSS v3评分:5.7,向量:AV:N/AC:L/PR:L/UI:R/S:U/C:H/I:N/A:N)

技术描述: 缓存支持的状态(state)/请求令牌(request-token)存储未与发起用户会话绑定,因此任何拥有有效状态值(可通过攻击者发起的认证流程轻松获取)的攻击者都可能实施CSRF攻击。当向OAuth客户端注册表提供缓存时,FrameworkIntegration.set_state_data方法将整个状态数据块存储在_state_{app}_{state}键下,而get_state_data方法则完全忽略调用者的会话。[1][2]

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
def _get_cache_data(self, key):
    value = self.cache.get(key)
    if not value:
        return None
    try:
        return json.loads(value)
    except (TypeError, ValueError):
        return None
[代码片段]
def get_state_data(self, session, state):
    key = f"_state_{self.name}_{state}"
    if self.cache:
        value = self._get_cache_data(key)
    else:
        value = session.get(key)
    if value:
        return value.get("data")
    return None

(来源:authlib/integrations/base_client/framework_integration.py:12-41)

因此,authorize_access_token中的检索操作会对任何呈现该不透明值的浏览器成功,并继续进行使用攻击者授权码的令牌交换。[3]

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
def authorize_access_token(self, **kwargs):
    """一步获取访问令牌。

    :return: 令牌字典。
    """
    params = request.args.to_dict(flat=True)
    state = params.get("oauth_token")
    if not state:
        raise OAuthError(description='Missing "oauth_token" parameter')

    data = self.framework.get_state_data(session, state)
    if not data:
        raise OAuthError(description='Missing "request_token" in temporary data')

    params["request_token"] = data["request_token"]
    params.update(kwargs)
    self.framework.clear_state_data(session, state)
    token = self.fetch_access_token(**params)
    self.token = token
    return token

(来源:authlib/integrations/flask_client/apps.py:57-76)

这为使用缓存支持存储的应用开启了登录CSRF的途径。根据依赖应用程序的实现方式(在登录CSRF情况下是否以某种方式链接账户),这可能最终导致账户接管。

[1] https://github.com/authlib/authlib/blob/260d04edee23d8470057ea659c16fb8a2c7b0dc2/authlib/integrations/flask_client/apps.py#L35 [2] https://github.com/authlib/authlib/blob/260d04edee23d8470057ea659c16fb8a2c7b0dc2/authlib/integrations/base_client/framework_integration.py#L33 [3] https://github.com/authlib/authlib/blob/260d04edee23d8470057ea659c16fb8a2c7b0dc2/authlib/integrations/flask_client/apps.py#L57

概念验证(PoC)

假设有一个应用——AwesomeAuthlibApp。假设该应用内部有这样的逻辑:当已登录用户执行回调请求时,会将新提供的SSO身份与发起请求的已存在用户关联起来。

那么,攻击者可以通过以下操作实现在该应用内的账户接管:

  1. 攻击者发起一个SSO OAuth流程,但在即将向AwesomeAuthlibApp发起回调调用之前停止;
  2. 攻击者诱骗一个已登录用户(通过网络钓鱼、路过式攻击等)使用攻击者的状态值和授权码向AwesomeAuthlibApp的回调端点发起一个GET请求。由于Authlib不检查状态令牌是否与执行回调的会话相关联,回调被处理,授权码被发送给提供者,账户关联操作随之发生。

在GET请求执行后,攻击者的SSO账户将与受害者的AwesomeAuthlibApp账户永久关联。

建议的修复方案

根据OAuth RFC [4],应将状态值与用户的会话绑定,以防止此类情况的发生。一种直接的缓解方法是,即使在使用缓存时,也将会话中的状态值继续存储在会话中。

另一种方法是将会话ID(或会话中的其他用户秘密)哈希到缓存键中。这样,状态将存储在缓存中,但仍与发起OAuth流程的用户的会话相关联。

[4] https://www.rfc-editor.org/rfc/rfc6749#section-10.12

参考链接

附加信息

报告者: davidbors-snyk 弱点: CWE-352 跨站请求伪造(CSRF) EPSS评分: 0.019%(第4百分位)

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计