在草案 20 中,提到了使用状态来防止 CSRF
到目前为止,我自己的实现这个 PHP 库的 Web 应用程序允许以下内容:
我是否需要对上述所有 3 种情况都使用状态?
如果是这样,什么是“状态”的好例子?
什么是好的“状态”?
有理想的长度吗?有最小长度吗?有最大长度吗?
有什么理想的妆容吗?字母数字包括大写?
在草案 20 中,提到了使用状态来防止 CSRF
到目前为止,我自己的实现这个 PHP 库的 Web 应用程序允许以下内容:
我是否需要对上述所有 3 种情况都使用状态?
如果是这样,什么是“状态”的好例子?
什么是好的“状态”?
有理想的长度吗?有最小长度吗?有最大长度吗?
有什么理想的妆容吗?字母数字包括大写?
逐步了解示例 CSRF 漏洞利用可能会有所帮助,以了解状态参数如何减轻此类攻击。在这个例子中, Mallory是攻击者,Alice是受害者。
Mallory 访问某个客户的网站并开始授权该客户使用 OAuth访问某个服务提供商的过程
客户请求服务提供商代表 Mallory 请求访问权限,该权限被授予
Mallory 被重定向到服务提供商的网站,她通常会在其中输入她的用户名/密码以授权访问
相反,Mallory 会捕获/阻止此请求并保存其 URL
现在,Mallory 以某种方式让 Alice 访问该 URL。如果 Alice 使用她自己的帐户登录到服务提供商,那么她的凭据将用于颁发授权码
授权码被交换为访问令牌
现在Mallory在客户端的账户被授权访问Alice在服务提供商的账户
那么,我们如何使用state
参数来防止这种情况呢?
客户端应该创建一个基于原始用户帐户的值(例如,用户会话密钥的哈希)。它是什么并不重要,只要它是独一无二的,并且是使用有关原始用户的一些私人的、不可猜测的信息生成的。
该值在上述第三步的重定向中传递给服务提供者
现在,当 Mallory 让 Alice 访问保存的 URL(上面的第五步)时,该 URL 包括state
使用 Mallory 的会话信息生成的参数
授权码在Alice 的会话中与 Mallory 的参数一起发布并发送回客户端state
state
客户端根据Alice 的会话信息生成一个新值,并将其与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));
请记住将其保存在您的会话中,以便稍后检查。