OAuth2.0 服务器栈如何使用状态来防止 CSRF?适用于草稿 2.0 v20


OAuth2.0 Server stack how to use state to prevent CSRF? for draft2.0 v20

我正在使用 PHP 库进行 OAuth2.0 v20

在草案20中,提到了使用状态来防止CSRF

到目前为止,我自己的实现此 PHP 库的 Web 应用程序允许以下内容:

  1. 使用授权代码请求的 3 条腿身份验证
  2. 使用资源所有者凭据授予的 2 腿身份验证
  3. 刷新访问令牌的请求

我需要对上述所有 3 种情况使用状态吗?

如果是这样,什么是"状态"的好例子?

什么是好的"状态"?

有理想的长度吗?任何最小长度?任何最大长度?

有理想的妆容吗? 字母数字,包括大写?

逐步

完成一个示例 CSRF 漏洞利用可能会有所帮助,以便了解状态参数如何缓解此类攻击。在这个例子中,马洛里攻击者爱丽丝受害者

攻击

  1. Mallory访问了一些客户的网站,并开始授权该客户使用OAuth访问某些服务提供商的过程

  2. 客户要求服务提供商允许代表马洛里请求访问,并授予

  3. 马洛里被重定向到服务提供商的网站,她通常会在其中输入用户名/密码以授权访问

  4. 相反,马洛里捕获/阻止此请求并保存其URL

  5. 现在,马洛里以某种方式让爱丽丝访问该网址。如果 Alice 使用自己的帐户登录到服务提供商,则她的凭据将用于颁发授权代码

  6. 授权代码交换为访问令牌

  7. 现在,马洛里在客户端上的帐户有权访问服务提供商上的爱丽丝帐户

那么,我们如何使用 state 参数来防止这种情况呢?

预防

  1. 客户端应以某种方式创建一个基于原始用户帐户的值(例如,用户会话密钥的哈希)。它是什么并不重要,只要它是唯一的,并且使用有关原始用户的一些私人的、无法猜测的信息生成即可。

  2. 此值在上述步骤 3 的重定向中传递给服务提供商

  3. 现在,当马洛里让爱丽丝访问保存的 URL(上面的第五步)时,该 URL 包含使用马洛里的会话信息生成的state参数

  4. 授权代码在 Alice 的会话中与 Mallory 的 state 参数一起发出并发送回客户端

  5. 客户端根据 Alice 的会话信息生成新的state值,并将其与从授权请求发回给服务提供商的state值进行比较。此值与请求上的 state 参数不匹配,因为该state值是根据 Mallory 的会话信息生成的,因此被拒绝。

攻击者不应能够为任何特定用户生成状态值,因此,诱骗用户访问其授权 URL 不会产生任何影响。

仅适用于 #1 -- 使用授权代码流的 3 条腿授权

当应用程序交换访问令牌的授权代码时,您希望确保导致提供的授权代码的 OAuth 流实际上是由合法用户启动的。 因此,在客户端应用程序通过将用户重定向到提供程序来启动 OAuth 流之前,客户端应用程序会创建一个随机状态值,并将其存储在服务器端会话中。 然后,当用户完成 OAuth 流时,请检查以确保状态值与存储在用户服务器端会话中的值匹配,因为这表示用户已启动 OAuth 流。

状态值通常应为伪随机不可猜测值。 一个简单的值可以用 PHP 中的 rand() 函数生成为 int,但你也可以变得更复杂以提供更大的保证。

该状态的存在是为了防止诸如我通过电子邮件向您发送包含我帐户授权代码的链接,您单击它以及应用程序将所有数据推送到我的帐户

而您不知道的事情。

OAuth 2.0 威胁模型文档中提供了一些其他信息:https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-threatmodel-00

特别是,请参阅有关CSRF保护的部分:https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-26#section-10.12

由于"状态"只是一个随机字符串,因此制作这样的东西应该可以解决问题:

$state = md5(uniqid(rand(), TRUE));

请记住将其保存在会话中,以便以后检查。