欢迎各位兄弟 发布技术文章

这里的技术是共享的

You are here

关于 Laravel CSRF 的问题求助 有大用

shiping1 的头像
首先这里有人提到过 http://stackoverflow.com/questions/28875788/laravel-5-auth-post-submit-tokenmismatchexception-in-verifycsrftoken-php-line

跟我的问题基本相同。

简单描述:

  1. 提交的表单中已经加入了 _token字段
  2. 开机-》打开浏览器-》进入网站,此时默认已登录,记住了上次的登录
  3. 然后提交了个form 就出现了 token miss match 的异常
public function handle($request, Closure $next)
{
    if ($this->isReading($request) || $this->tokensMatch($request))
    {
        return $this->addCookieToResponse($request, $next($request));
    }

    throw new TokenMismatchException;
}

抛出异常的位置,最后的那个throw,进一步跟入$this->tokensMatch方法发现

return StringUtils::equals($request->session()->token(), $token); 

这个反回false,也就是我每次产生的token和session中得token会不一致。

这里就不理解了,如果我浏览器一直开着,session不过期,那么每次提交又都会生成新的token,是不是每次都会验证失败?

想到这个地方有点乱了,是不是哪个地方进入误区了? 向大家求助....

update:

前面理解错了一个地方,csrf()那个函数原来就是从session中取的token,当成是每次随机生成了.这样的话可能不知道什么原因导致token变了。

回复数量: 16
  • Summer
    Summer • 1年前 •  • 

    排版好乱, Markdown 不会用?

  • argb
    argb • 1年前 •  • 

    @Summer 真没用过,一时不太习惯,惰性

  • argb
    argb • 1年前 •  • 

    @Summer 改了下,克服懒惰,谢summer提醒.

  • Summer
    Summer • 1年前 •  • 

    排版很重要, 因为排版是在尊重查看帖子的人 :smile:

    CSRF Token 存储在 Session 里, 每一次 Session 初始化的时候, 都会检查 _token 是否存在, 否的话regenerateToken 下

    file

    下面是 regenerateToken 的定义:

    file

    可以理解为 CSRF Token 是依赖于 Session.

    Session 过期, 或者 Session 里 _token 被删除的话, CSRF Token 就会被重新生成, 如果这个时候刚好有一个 无效的 _token 请求进来的话, 就会造成 Token Mismatch.

    一般都是 Session 过期造成的, Session 过期时间 L4 默认设置如下:

    file

  • argb
    argb • 1年前 •  1 • 

    @Summer 恩 谢谢summer解答

    如果是这种情况的话还是有一定几率发生的,从google的结果看确实也不少人碰到这个问题。按说如果我重新载入页面,这个问题应该就没有了,忘记当时有没有刷新页面了,后面碰到的话在研究下。

    可能需要捕获下这个异常做处理,否则一旦发生用户体验比较差。

  • argb
    argb • 1年前 •  • 

    复现了,还是什么也没做,突然不行了 刷新页面后重新提交也没用,每次刷新后会去取到一个新的_token值,但是验证的时候还是不一样,每次请求_token值都不同,但明明是session没过期,不知道是不是bug。

  • farrah8888
    farrah8888 • 1年前 •  • 

    我也遇到这样的问题,写的论坛很多人突然表示登录或者发表文章之后就出现token miss match的错误,我按照stackoverflow的一个方法把filter里面的csrf改成了

    Route::filter('csrf', function() {

    // no auto check on posts

    });

    Route::filter('mycsrf', function() {

    if (Session::token() !== Input::get('_token'))
    {
        throw new Illuminate\Session\TokenMismatchException;
    }

    }); 暂时就好了 但总觉得不是长久之计,因为我不明白这是为什么造成的。。。。也来求个解决的方法

  • argb
    argb • 1年前 •  • 

    @farrah8888 我也是临时回避了下 跟了下也没查出原因,有点像bug,感觉我git更新下服务器的代码后就会出问题,比较诡异,后面有时间了在研究下。

  • adu42
    adu42 • 9个月前 •  • 

    好了,哥来做个总结,不是什么大问题: Session 是用Store方式存放的,那么不可能实时保存,laravel的机制是在管道(pipeline)的末端保存。各位出现TokenMismatchException 是因为Session每次取完token都没有保存,在中间不是return string或继续执行,而是exit或者结束等,所以大家看到token总是在变。

    请让你的程序不要在管道中间终止。

  • windyang
    windyang • 7个月前 •  • 

    也遇到这个问题,搜了下,session不持久导致的TokenMismatchException错误,还有auth登陆后,再刷新几次,auth check就不是登陆状态了。有人解决了吗?

    时好时坏,感觉是个bug.

  • sj1370201
    sj1370201 • 6个月前 •  • 

    @windyang @argb 我也遇到了 你们解决了吗

  • argb
    argb • 6个月前 •  • 

    @sj1370201 好久没发生了

  • rickytheone
    rickytheone • 5个月前 •  • 

    我也是在ajax处理文件上传的时候遇到,无论怎么弄,就是出现500错误,总是mismatch token,有高手解决了的麻烦分享一下经验

  • argb
    argb • 5个月前 •  • 

    @rickytheone 你的是另一个问题,ajax 上传你要加一个专门的http头

    <meta name="csrf-token" content="{{ csrf_token() }}" />

         /**
         * don't remove this setup
         */
        $.ajaxSetup({
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
            }
        });
  • rickytheone
    rickytheone • 5个月前 •  • 

    添加了,后来发现是浏览器开启了data cache才导致问题,全部清理一次就好了

  • argb
    argb • 5个月前 •  • 

    @rickytheone OK,解决就好 :blush:

来自 https://phphub.org/index.php/topics/640
普通分类: