在带有 PKCE 的 OpenID Connect 中,客户端如何知道在用户重定向后发送哪个 code_verifier 和哪个授权码?
In OpenID Connect with PKCE, how does the client know which code_verifier to send with which authorization code after user redirect?
我正在学习有关 OpenID Connect 授权代码工作流程的 ASP.NET 安全课程,以及针对代码重放攻击的 PKCE 保护。这个过程有一个方面我不明白。
过程:
依赖客户端生成 PKCE code_verifier,将其散列到 code_challenge,并使用 code_challenge 作为查询参数将用户发送到授权服务器。
授权服务器存储code_challenge,发布授权码,并使用授权码将用户重定向回客户端。
客户端将授权码连同原来的code_verifier一起发送,换取token。授权服务器在颁发令牌之前验证 code_verifier 确实散列到 code_challenge。
我的问题是第 3 步:由于 HTTP 是无状态的,客户端如何知道要发送哪个 code_verifier 和授权码? code_verifier 是否存储在用户代理的 cookie 中?
PKCE 最初是为移动客户端设计的,它们通常只发出一个授权请求。但现在推荐所有使用授权码流程的客户端。
你说得对,如果客户端是一个为许多用户提供服务的 Web 应用程序,则客户端应用程序需要将正确的 code_verifier 与授权请求相关联。
正如您所说,客户端可以将 code_verifier 存储在 cookie 中,因此它将与授权码一起发送给客户端。
或者它可以将其存储在客户端的服务器端,并将状态参数中的密钥粘贴到授权请求中。如果与授权请求一起传递,状态将成为对 redirect_uri 调用的一部分。
使用 cookie 来存储“代码验证器”似乎违反了 OpenId 规范的精神,而且似乎是一个很大的安全漏洞。
简而言之,该规范希望您使用S256对代码验证器进行散列,并将代码验证器保密以防止窃听或被猜到。
PKCE RFC Section 7.1 说“安全模型依赖于攻击者未学习或猜测代码验证程序这一事实。坚持遵守这一点至关重要这个原则。因此,代码验证器必须以加密随机且具有高熵的方式创建,攻击者无法猜测。”
...“使用“S256”可防止向攻击者泄露“code_verifier”值。”
现在,如果您加密“代码验证器”,它确实允许使用 cookie。这是规范中的内容
Section 7.2: "如果代码质询方法是"plain"并且代码质询是returned inside authorization"code"以实现无状态服务器,它必须以只有服务器才能解密和提取它的方式进行加密。"
好吧,OpenId 规范有一个解决方案,Microsoft 也提供了一个可遵循的实现。调用“授权”端点时,请参考 OpenId 规范中的“state”参数。身份提供者会将 return 值返回给调用者。
在 .NET Core 中完成的方式是使用“state”查询字符串参数,其中值是一个字典但受保护(加密)。如需帮助,请查看 .NET 核心代码并查看“Microsoft.AspNetCore.Authentication.OAuth.OAuthHandler”
中的方法“BuildChallengeUrl”
另外,这个 Site 有一个很棒的想法。这是一个有效的选项。
我正在学习有关 OpenID Connect 授权代码工作流程的 ASP.NET 安全课程,以及针对代码重放攻击的 PKCE 保护。这个过程有一个方面我不明白。
过程:
依赖客户端生成 PKCE code_verifier,将其散列到 code_challenge,并使用 code_challenge 作为查询参数将用户发送到授权服务器。
授权服务器存储code_challenge,发布授权码,并使用授权码将用户重定向回客户端。
客户端将授权码连同原来的code_verifier一起发送,换取token。授权服务器在颁发令牌之前验证 code_verifier 确实散列到 code_challenge。
我的问题是第 3 步:由于 HTTP 是无状态的,客户端如何知道要发送哪个 code_verifier 和授权码? code_verifier 是否存储在用户代理的 cookie 中?
PKCE 最初是为移动客户端设计的,它们通常只发出一个授权请求。但现在推荐所有使用授权码流程的客户端。
你说得对,如果客户端是一个为许多用户提供服务的 Web 应用程序,则客户端应用程序需要将正确的 code_verifier 与授权请求相关联。
正如您所说,客户端可以将 code_verifier 存储在 cookie 中,因此它将与授权码一起发送给客户端。
或者它可以将其存储在客户端的服务器端,并将状态参数中的密钥粘贴到授权请求中。如果与授权请求一起传递,状态将成为对 redirect_uri 调用的一部分。
使用 cookie 来存储“代码验证器”似乎违反了 OpenId 规范的精神,而且似乎是一个很大的安全漏洞。
简而言之,该规范希望您使用S256对代码验证器进行散列,并将代码验证器保密以防止窃听或被猜到。
PKCE RFC Section 7.1 说“安全模型依赖于攻击者未学习或猜测代码验证程序这一事实。坚持遵守这一点至关重要这个原则。因此,代码验证器必须以加密随机且具有高熵的方式创建,攻击者无法猜测。” ...“使用“S256”可防止向攻击者泄露“code_verifier”值。”
现在,如果您加密“代码验证器”,它确实允许使用 cookie。这是规范中的内容 Section 7.2: "如果代码质询方法是"plain"并且代码质询是returned inside authorization"code"以实现无状态服务器,它必须以只有服务器才能解密和提取它的方式进行加密。"
好吧,OpenId 规范有一个解决方案,Microsoft 也提供了一个可遵循的实现。调用“授权”端点时,请参考 OpenId 规范中的“state”参数。身份提供者会将 return 值返回给调用者。
在 .NET Core 中完成的方式是使用“state”查询字符串参数,其中值是一个字典但受保护(加密)。如需帮助,请查看 .NET 核心代码并查看“Microsoft.AspNetCore.Authentication.OAuth.OAuthHandler”
中的方法“BuildChallengeUrl”另外,这个 Site 有一个很棒的想法。这是一个有效的选项。