每个请求或不是新的CSRF令牌?

时间:2012-05-05 21:46:55

标签: php csrf

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

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

但是让我们说每小时生成一个令牌更好,然后我需要两个会话:令牌,到期,

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

5 个答案:

答案 0 :(得分:34)

如果您按照表单请求执行此操作,那么您基本上会删除发生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!!!
}

因为它是“每个表单” - 你不会得到双重表单提交 - 因为你可以在第一次提交表单后擦除令牌!

答案 1 :(得分:12)

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

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

但限制有效性的缺点是它可能导致误报,从而限制可用性,例如: G。一个合法的请求可能会使用一个令牌,该令牌因为令牌请求时间过长而已经失效,或者该令牌已经被频繁使用。

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

答案 2 :(得分:1)

你的问题的答案是:它取决于。

您不需要将会话用于定时令牌,您只需在服务器上使用服务器时间和密钥即可。

  

但是让我们说每小时生成一个令牌更好,然后我需要两个会话:令牌,到期,

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

然后提交表单并且您现在和之前的30分钟时段验证令牌。因此,令牌有​​效期为30分钟至一小时。

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

答案 3 :(得分:0)

您可以使用这两种方法。

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

2)您可以在每个用户会话中使用一个令牌(无需每小时执行一次),这样可以更容易实现。您不会遇到同步问题,但如果令牌不太强,则可以猜到。如果令牌非常随机,那么对于男性来说,实际上要求伪造的人很难。

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

答案 4 :(得分:0)

owasp网站上,它提到了

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

结论是

CSRF令牌应为:

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