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

Joh*_*ohn 34 php csrf

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

$data['token'] = md5(uniqid(rand(), true));
$_SESSION['token'] = $data['token'];
Run Code Online (Sandbox Code Playgroud)

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

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

Lau*_*nce 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!!!
}
Run Code Online (Sandbox Code Playgroud)

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

  • "那么上面的攻击可能会奏效"---怎么样?请详细说明(这个**不正确的**答案不应该被赞成,因为回答者不知道用什么csrf-token) (14认同)
  • 攻击者如何知道csrf-token值?"CSRF预防的全部要点是使每个表格令牌都独一无二" - 不,你错了. (13认同)
  • 让我们[在聊天中继续讨论](http://chat.stackoverflow.com/rooms/10926/discussion-between-laurencei-and-zerkms) (5认同)
  • 表单应包含csrf-token,即基于csrf-token的保护工作方式.攻击者无法知道它.在继续讨论之前,我建议您稍微阅读一下 (3认同)

Gum*_*mbo 13

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

如果您害怕令牌可能被攻击网站泄露或获得(例如通过XSS),您可以将令牌的有效性限制为特定时间范围,特定表格/ URL或一定数量的使用.

但是限制有效性的缺点在于它可能导致误报并因此限制可用性,例如.G.一个合法的请求可能会使用一个令牌,该令牌因为令牌请求太久以前已经失效,或者该令牌已经被频繁使用.

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