我们在网站上遇到此问题,我们从用户那里随机收到了CSRF错误。会话cookie和会话数据设置为在12小时内过期,会话驱动程序设置为使用Redis。在我们的调查之后,我们最终成功地模拟了异常情况,所以这是场景:
用户在网站上打开两个不同的页面,使用Chrome浏览器,打开“打开上次关闭的标签”设置。其中一个页面上有一个表单(例如登录),然后用户在某个时刻退出浏览器。他第二天重新打开浏览器(12小时过去,因此会话cookie和会话数据已过期)Chrome尝试重新加载所有打开的页面。它向服务器发送两个同时发出的请求,而它们都没有会话cookie。在服务器端,Laravel为每个会话ID生成两个不同的会话ID。 Chrome接收它们并覆盖其他会话cookie上的一个。一旦用户尝试提交表单(例如登录),它就会在表单会话cookie被覆盖时生成CSRF错误。
我们也有一些AJAX帖子请求,由于这种情况我们失败了CSRF错误。
我想知道Laravel是否能够以安全的方式为两个请求生成相同的会话ID。
有没有人有任何想法我们如何解决这个问题?
P.S:我们正在使用laravel 4.1和这个会话配置:
return array(
'driver' => 'redis',
'lifetime' => 720,
'expire_on_close' => false,
'files' => storage_path().'/sessions',
'connection' => null,
'table' => 'sessions',
'lottery' => array(2, 100),
'cookie' => 'laravel_session',
'path' => '/',
'domain' => '.ourdomain.com',
);
答案 0 :(得分:14)
经过对我们公司问题的大量调查,我得出了这个结果,我希望它有所帮助,首先这里是我们的环境规范:
首先,似乎TokenMistmatch异常发生在各种不同的条件下,我几乎研究了所有这些异常,并且能够解决其中的一些,一些取决于会话背后的逻辑,一些可能是错误。在下文中,我将解释我所遇到的每种情况。
<强> 1。已过期的会话
让我们说你已经将你的会话配置了3个小时,用户打开一个表格,由于某种原因他离开了电脑(喝杯咖啡)所以在会议结束3小时后他试图提交表单并获取令牌例外。这就是为什么每个人一旦进入同时获得令牌错误,无论应用程序有多稳定,我可以想象有两种方法可以防止它,并且他们会及时使用ajax更新会话cookie,或者增加会话到达相当长的时间。
<强> 2。会话过期时的并发请求
有时在第一页的加载时发生并发请求,例如用户在chrome上打开了两个不同的选项卡,当他重新打开时,chrome chrome同时发送请求,或者您可能在第一个加载时有多个并发的ajax请求您的申请页面。所以请注意,会话cookie是在收到第一个响应后收到的,但您可以在此之前发送下一个请求,因此您将在每个请求上获得一个新会话(新cookie),这可能会导致令牌异常,如果其中一个请求填充表单。您可以根据它的来源阻止此方案,例如,如果ajax请求导致问题并且您没有在ajax响应中使用会话,则可以禁用在请求为ajax时发送会话cookie,在第二个方案(多次单击提交按钮),您可以在提交按钮后立即禁用该按钮。
第3。登录时的并发请求
当登录发生时,出于安全原因,laravel会更改会话ID,复制会话数据和DESTROYS THE LAST SESSION,因此在登录并发请求时会出于某种原因(多次单击登录按钮),因此会话ID将重新生成多次并DESTROYS在服务器端最后生成的会话,因为其中一些请求仍然使用先前的会话ID(服务器端不再存在)它导致重新生成CSRF令牌,请注意通常如果laravel可以在guest(未登录)会话中找到令牌,则laravel不会在登录时重新生成令牌,但在这种情况下,由于guest虚拟机会话被销毁,因此它将重新生成令牌,并且可能导致其他令牌异常使用原始令牌的请求。另请注意,此问题不仅会导致令牌异常,还会导致用户在一次请求后被注销,因为并发请求可以更改登录的会话。我通过在Illuminate\Auth\Guard:updateSession
:
protected function updateSession($id)
{
$this->session->put($this->getName(), $id);
//$this->session->migrate(true);
$this->session->migrate()
}
将true传递给会话存储的migrate方法将导致在迁移后销毁服务器上的会话,所以现在数据将保留在服务器上并在其到期时间而不是在此请求上销毁,它将解决问题。我不知道我们是否可以将其称为laravel中的错误,但我想我们可以为此提出更好的解决方案。
<强> 4。浏览器强>
调查日志之后发现其中一些令牌例外是因为用户的浏览器不接受会话cookie,我在iOS Safari上看到的最多,我相信这是我们无能为力的事情。< / p>
<强> 5。 Redis bug
我们服务器上的一些令牌例外是因为redis,因为某些原因,laravel在打开会话时无法从redis服务器读取会话数据,因此会导致CSRF令牌的重新生成。它是在我们的服务器上随机发生的,所以我尝试更改会话驱动程序,这种类型的异常逐渐消失。我尝试过数据库,apc和文件驱动程序,没有人产生这个问题。我还没有找到导致错误的原因,但我认为它可能是redis或predis库的错误。 (如您所知,由于兼容性问题,laravel 4.1未使用最新版本的predis。)
好的,这是我过去两个月在这个问题上的经历。我希望它可能改变你对这个问题的解决方案的观点,最重要的是令牌异常不会发生,因为一个原因可能是多个问题的结果。如果您遇到类似事件或者您有新事物,请与我分享。
答案 1 :(得分:0)
我已经多次遇到过这个问题,没有具体原因,Amir没有提到。
清除域cookie适用于我看到的场景。
答案 2 :(得分:0)
在我的情况下,这是缓存配置文件的问题。 Laravel创建一个缓存在bootstrap / cache文件夹中的配置文件。将此config.php文件重命名为其他内容并运行“php artisan cache:clear”
然后运行该网站,它应该可以正常工作
答案 3 :(得分:0)
这可能与这个众所周知的问题有关
Laravel 5.0 - Asyncronous AJAX Requests cause Session Variable Changes to be Overwritten #7549
如果多个请求尝试覆盖会话并且会话文件没有锁定,则可能导致会话文件损坏(覆盖)。