【问题标题】:New CSRF token per request or NOT?每个请求是否有新的 CSRF 令牌?
【发布时间】:2012-05-15 00:37:17
【问题描述】:

所以我正在阅读并且对拥有 CSRF 令牌感到非常困惑,我应该为每个请求生成一个新令牌,还是每小时生成一个新令牌?

$data['token'] = md5(uniqid(rand(), true));
$_SESSION['token'] = $data['token'];

但是假设最好每小时生成一个令牌,那么我需要两个会话:令牌,到期,

我将如何处理表格?只需将 echo $_SESSION['token'] 放在隐藏值表单上,然后在提交时进行比较?

【问题讨论】:

  • 请注意,如果用户同时在两个不同的浏览器窗口中打开您的应用程序,则为每个请求生成一个新令牌可能会导致问题。令牌将不同步。
  • @Michael 这个问题可以通过推送技术,html 5 通信标准来解决。
  • 如果安全性不高,只需取一个哈希值,例如用户的 ip 和他的密码哈希。这可能永远不会或很少改变,但它仍然可以发挥作用,因为攻击者不会知道用户的密码(如果知道,他不需要对他执行 CSRF 攻击)
  • @ThiefMaster:有什么理由对真实数据(如用户的 ip 或密码)进行哈希处理而不生成随机数据?
  • 是的,这样你就不需要存储令牌了。而且它不会经常更改 => 对于使用后退按钮和多个标签的用户来说更舒适。

标签: php csrf


【解决方案1】:

您的问题的答案是:视情况而定。

而且你不需要使用会话来获取定时令牌,你可以只使用服务器时间和服务器上的密钥。

但是假设最好每小时生成一个令牌,那么我需要两个会话:令牌,到期,

不,您需要一个能够在某个时间范围内生成令牌的例程。假设您将时间划分为每 30 分钟。您在表单中为当前 30 分钟创建一个令牌。

当提交表单并且您针对现在和之前的 30 分钟时间段验证令牌时。因此,令牌的有效期为 30 分钟到一小时。

$token = function($tick = 0) use($secret, $hash) {
    $segment = ((int) ($_SERVER['REQUEST_TIME'] / 1800)) + $tick;
    return $hash($secret . $segment);
};

【讨论】:

  • @John 根据您的需要,如果基于 $_SESSION 的方法适合您,那就去做吧。我曾经用它来保护下载的热链接,效果很好。
  • @john:我添加了一个示例函数,如何使用会话生成在特定时间段内有效的令牌。
  • 具有 30 分钟 TTL 的 CSRF 令牌与 24 小时 TTL 令牌和 1 分钟 ttl 令牌一样安全。但是 TTL 越少 - 用户越有机会捕获 CSRF 令牌无效的情况。所以我投票给每个会话 1 个 CSRF 令牌,没有失效/重新生成
  • @zerkms - 你说得对,30 分钟堪称典范。通常会话确实会在 60 分钟内过期,因此基于会话的 CSRF 令牌也有类似的东西(尽管随着每次交互的超时时间延长,它的行为会有所不同)。但是,每个小时后,会话 ID 也应该重新生成,以防止会话可以无限制地打开。
  • -1 这不能防止 CSRF 攻击。攻击站点只需要自己从服务器获取有效令牌即可。
【解决方案2】:

如果您根据表单请求执行此操作 - 那么您基本上消除了发生 CSRF 攻击的能力并且您可以解决另一个常见问题:多个表单提交

简单来说 - 如果用户在提交之前要求表单输入,您的应用程序将只接受表单输入。

正常情况: 用户 A 访问您的网站,并要求提供表格 A,并获得表格 A 以及表格 A 的唯一代码。当用户提交表格 A 时,他/她必须包含仅用于表格 A 的唯一代码。

CSRF 攻击场景: 用户 A 访问您的网站,并请求表单 A。与此同时,他们访问了另一个“不良”站点,该站点尝试对他们进行 CSRF 攻击,让他们提交一个伪造的 B 表。

但是您的网站知道用户 A 从未询问过表单 B - 因此即使他们有表单 A 的唯一代码,表单 B 也会被拒绝,因为他们没有表单 B 唯一代码,只有表单 A 代码.您的用户很安全,您可以在晚上轻松入睡。

但是,如果您将其作为通用令牌进行,持续一个小时(就像您在上面发布的那样) - 那么上面的攻击可能会起作用,在这种情况下,您的 CSRF 保护并没有取得太多成就。这是因为应用程序一开始并不知道表单 B 从未被要求过。它是一个通用令牌。 CSRF 预防的全部要点是使每个表单令牌对该表单唯一

编辑:因为您要求提供更多信息: 1 - 您不必根据表单请求执行此操作,您可以按小时/会话等执行此操作。重点是提供给用户的秘密值,并在返回时重新提交。此值不为其他网站所知,因此无法提交虚假表单。

因此,您可以为每个请求或每个会话生成令牌:

// Before rendering the page:
$data['my_token'] = md5(uniqid(rand(), true));
$_SESSION['my_token'] = $data['my_token'];

// During page rendering:
<input type="hidden" name="my_token" id="my_token" value="<? php echo $_SESSION['my_token']?>" />

// After they click submit, when checking form:
if ($_POST['my_token'] === $_SESSION['my_token'])
{
        // was ok
}
else
{
          // was bad!!!
}

而且因为它是“按表单” - 您不会收到双重表单提交 - 因为您可以在第一次提交表单后擦除令牌!

【讨论】:

  • "那么上面的攻击可能会奏效" --- 怎么样?请详细说明(这个不正确的答案不应该被投票,因为回答者不知道 csrf-token 的用途)
  • 因为如果你有通用的 CSRF 令牌,那么只要黑客让用户 A 提交表单 B,它就会成功,因为应用程序不知道表单 B 从未被请求过地方。它是一个通用令牌。 CSRF 预防的全部要点是使每个表单令牌对该表单唯一。
  • 攻击者如何知道 csrf-token 的值? “CSRF 预防的全部要点是让每个表单令牌对那个表单都是唯一的”——不,你错了。
  • 表单应该包含 csrf-token,这就是基于 csrf-token 的保护的工作方式。而攻击者无从知晓。我建议您在继续讨论之前先阅读一下它
【解决方案3】:

通常,每个用户或每个会话拥有一个令牌就足够了。重要的是,令牌只绑定到一个特定的用户/会话,而不是全局使用。

如果您担心令牌可能会被攻击站点(例如通过 XSS)泄露或获取,您可以将令牌的有效性限制在某个时间范围、某个表单/URL 或某个使用量。

但限制有效性的缺点是可能导致误报,从而限制可用性,例如。 G。合法请求可能使用刚刚失效的令牌,因为令牌请求太久以前或令牌已经被使用太频繁了。

所以我的建议是每个用户/会话只使用一个令牌。如果您想要进一步的安全性,请为每个用户/会话的每个表单/URL 使用一个令牌,这样如果一个表单/URL 的令牌泄露,其他的仍然是安全的。

【讨论】:

  • 请定义“每个用户”。那是什么意思?有什么资格成为用户?您指的是基于 IP 的用户跟踪吗?
  • @hakre 您通常会使用会话将令牌与会话相关联。但是有用户帐户,您也可以将令牌直接关联到用户。这就是我所说的“每个用户”。
  • 会议呢?通过 cookie 识别?这不会在这种情况下留下一个漏洞吗?我的意思是只要会话标识符可以在请求中传递,这是行不通的,对吧?尽管给出的信息对指导很有用,但只是想绕一圈。
  • @hakre 不,会话仅用于将令牌与请求相关联,并且两者必须相等才能使请求真实。
  • @Gumbo 在成功提交任何表单或更改用户权限后重新生成令牌不是一个好主意吗?
【解决方案4】:

您可以同时使用这两种方法。

1) 每个请求的随机令牌。为了解决令牌不同步的问题,您可以使用服务器发送事件http://www.w3.org/TR/eventsource/或websocketshttp://www.w3.org/TR/websockets/通信技术实时更新每个页面的令牌。

2) 您可以为每个用户会话使用一个更易于实施的令牌(无需每小时执行一次)。你不会有同步问题,但如果令牌不是太强,它可以被猜到。当然,如果令牌是非常随机的,那么受恶意攻击的人将很难真正进行请求伪造。

附:第一种方法是最安全的,但它更难实现并且使用更多的资源。

【讨论】:

    【解决方案5】:

    owasp 网站提到了这一点

    按请求令牌比按会话令牌更安全 攻击者利用被盗令牌的范围很小。 但是,这可能会导致可用性问题。

    它的结论是

    CSRF 令牌应该是:

    • 每个用户会话唯一。
    • 秘密
    • 不可预测(安全方法生成的大随机值)。

    【讨论】:

      猜你喜欢
      • 2019-07-12
      • 2014-01-06
      • 2018-11-22
      • 2013-04-25
      • 2012-09-18
      • 2016-10-15
      • 2014-12-13
      • 2012-11-04
      • 2016-06-21
      相关资源
      最近更新 更多