听起来您反对只要浏览器打开就让会话保持打开状态是自动攻击的问题。不幸的是,在每个页面加载时刷新令牌只能阻止最业余的攻击者。
首先,我假设我们正在讨论专门针对您的网站的攻击。 (如果我们谈论的是那些只是四处游荡并提交各种表格的机器人,这不仅不会阻止他们,而且还有更好、更简单的方法来做到这一点。)如果是这样的话,我的目标是我的网站,这是我的机器人会做的事情:
- 加载表单页面。
- 读取表单页面上的令牌。
- 使用该令牌提交自动请求。
- 转到步骤 1。
(或者,如果我对您的系统进行了足够的调查,我会意识到,如果我在每个请求中包含“这是 AJAX”标头,我可以永远保留一个令牌。或者我会意识到该令牌是我的会话 ID,并且发送我自己的PHPSESSID
曲奇饼。)
这种在每次页面加载时更改令牌的方法绝对无法阻止实际上的人wanted如此严重地攻击你。因此,由于代币对自动化没有影响,所以重点关注它对 CSRF 的影响。
从阻止 CSRF 的角度来看,创建一个令牌并维护它直到用户关闭浏览器似乎就完成了所有目标。简单的 CSRF 攻击被击败,用户能够打开多个选项卡。
TL;DR:在每个请求上刷新一次令牌并不能提高安全性。追求可用性并在每个会话中执行一个令牌。
然而!如果您非常担心重复的表单提交(无论是意外还是其他原因),这个问题仍然可以轻松解决。答案很简单:将两个令牌用于两个不同的工作。
第一个令牌将保持不变,直到浏览器会话结束。该令牌的存在是为了防止 CSRF 攻击。该用户使用此令牌提交的任何内容都将被接受。
第二个令牌将为加载的每个表单唯一生成,并将存储在打开表单令牌的用户会话数据的列表中。该Token具有唯一性,一旦使用即失效。该用户使用此令牌提交的内容将被接受一次且仅一次。
这样,如果我打开表单 A 的选项卡和表单 B 的选项卡,每个选项卡都会有我个人的反 CSRF 令牌(已处理 CSRF)和我的一次性表单令牌(已处理表单重新提交)。这两个问题均得到解决,且不会对用户体验产生任何不良影响。
当然,您可能会认为对于这样一个简单的功能来说,实现起来太多了。无论如何,我认为是这样。无论如何,如果你想要的话,就存在一个可靠的解决方案。