使用 PKCE 的授权代码流如何比没有 client_secret 的授权代码流更安全

问题描述

很可能我对这个主题有误解或在实施过程中遗漏了一些东西

我阅读了 Auth0 的文档,用于通过端点而不是 SDK 创建带有 PKCE 的授权代码流,我看到我们提出了如下挑战和验证器(来自 auth0 文档):

In [2]: from json import loads

In [3]: from dicttoxml import dicttoxml

In [4]: json_obj = '{"main" : {"aaa" : "10","bbb" : [1,2,3]}}'

In [5]: xml = dicttoxml(loads(json_obj))

In [6]: print(xml)
<?xml version="1.0" encoding="UTF-8" ?><root><main type="dict"><aaa type="str">10</aaa><bbb type="list"><item type="int">1</item><item type="int">2</item><item type="int">3</item></bbb></main></root>

In [7]: xml = dicttoxml(loads(json_obj),attr_type=False)

In [8]: print(xml)
<?xml version="1.0" encoding="UTF-8" ?><root><main><aaa>10</aaa><bbb><item>1</item><item>2</item><item>3</item></bbb></main></root>

// Dependency: Node.js crypto module
// https://nodejs.org/api/crypto.html#crypto_crypto
function base64URLEncode(str) {
    return str.toString('base64')
        .replace(/\+/g,'-')
        .replace(/\//g,'_')
        .replace(/=/g,'');
}
var verifier = base64URLEncode(crypto.randomBytes(32));

然后我们将挑战传递给授权端点,如下所示(来自 auth0 doc):

// Dependency: Node.js crypto module
// https://nodejs.org/api/crypto.html#crypto_crypto
function sha256(buffer) {
    return crypto.createHash('sha256').update(buffer).digest();
}
var challenge = base64URLEncode(sha256(verifier));

并将代码和验证器传递给令牌端点,如下所示(再次来自 auth0 doc):

https://YOUR_DOMAIN/authorize?
    response_type=code&
    code_challenge=CODE_CHALLENGE&
    code_challenge_method=S256&
    client_id=YOUR_CLIENT_ID&
    redirect_uri=YOUR_CALLBACK_URL&
    scope=ScopE&
    audience=API_AUDIENCE&
    state=STATE

实现是一件相当简单的事情,但我不明白另一个应用程序如何不能进行相同的挑战和验证并模拟我们的应用程序?

我认为我们不使用 client_secret 作为授权代码流,暴露的 client_secret 使黑客更容易尝试生成令牌并错误地模拟我们的应用程序,为什么他们不能简单地模拟挑战和验证者?

解决方法

如果您在应用程序或 SPA 中使用没有 PKCE 的授权代码流,并且有人捕获了您从授权服务器收到的授权代码,他将能够从授权中检索访问令牌通过向授权服务器发送授权码 + 客户端 ID(密钥)和客户端密钥来获取令牌。因为 ID 和密钥对于您应用的所有用户/客户端相同。有了访问令牌,他就可以从资源服务器检索用户数据。

如果您将授权代码流与 PKCE 一起使用,攻击者将无法使用授权代码,因为他没有验证器。如果他创建自己的验证程序和代码挑战并构建自己的应用程序版本,他还需要让用户使用他的应用程序版本。只有在用户登录授权服务器后,质询和验证器才会匹配。 如果他只是以某种方式捕获授权代码,那么生成自己的质询和验证器是没有用的,因为流程是从您的应用创建的质询开始的,与他创建的验证器不匹配。

与此问题相关的:Can't an attacker also get the code challenge?

What is PKCE trying to do?

,

PKCE 就是验证发起初始身份验证请求的客户端是否与使用授权码获取真实令牌的客户端相同。

PKCE 是一种在身份提供者端实施的保护检查,与需要客户端进行检查的 State/Nonce 安全功能相比。

PKCE 与客户端机密完全无关。