最近发现服务器上 Laravel日志中 TokenMismatchException的报错有点多 找了下原因和资料 来做个小小总结把
先来讲下 CSRF 攻击
CSRF(Cross-site request forgery),中文名称:跨站请求伪造,也被称为:one click attack/session riding,缩写为:CSRF/XSRF
大概就是 攻击者盗用用户身份,发送恶意请求 来达到攻击者的一些目前 造成用户的隐私以及财产损失啦等等
CSRF攻击需要满足
1.用户登录受信任网站A,并在本地生成Cookie。
2.用户在不登出A的情况下,访问危险网站B。
具体的可以去下面看下 浅谈CSRF攻击方式 这篇文章写的很详细有兴趣的可以去看下
Laravel CSRF令牌
Laravel 自动为每一个被应用管理的有效用户会话生成一个 CSRF “令牌”,该令牌用于验证授权用户和发起请求者是否是同一个人。把这个令牌放入 form表单 的隐藏域中提交的时候一起提交
Laravel中提供了帮助函数csrf_field
来帮助我们添加 csrf 令牌
在模版文件使用
该辅助函数会帮我们生成对应HTML
代码如下:
|
|
也可以使用blade
模版引擎的方式:
|
|
不需要我们自己去编写后台的验证代码,Laravel使用了自带的中间件VerifyCsrfToken
将请求中输入的 token 值和 Session 中的存储的 token 作对比来进行验证 更多Laravel这个中间件的详细用法请看 Laravel路由
VerifyCsrfToken 中间件
在Laravel 5.1及更高的版本中VerifyCsrfToken
中间件已经被加入到了中间件组web
中 在app/Http/Kernel.php
中可以看到
|
|
然后我们可以看到在RouteServiceProvider.php
中默认加载了web
中间件组 也就是我们所有的请求都会被这个中间件校验 如果你是做API
接口的项目可以把这个中间件屏蔽掉 直接注释掉
TokenMismatchException 产生的原因
回到正题 关于 TokenMismatchException 产生的原因大概总结了以下
1.表单请求中没有带上校验token
2.被人攻击了 请求中伪造的token或者没有token导致的校验不通过
3.session过期 [这个比较坑找了好久]
在config/session.php
文件中可以看到默认的session时间是120分钟 其实这个已经足够了 如果不满意自己加吧 这个默认时间单位是分钟哦
回到VerifyCsrfToken.php
中 我们可以看到它实际上是继承自Illuminate\Foundation\Http\Middleware\VerifyCsrfToken
这个父类,具体的生成 token 以及对 token 的校验都是在这里完成的 在它父类的大概第 55 行左右
|
|
TokenMismatchException
就是在这里被抛出
解决办法
对于第一种错误 可以直接在表单提交的时候带上校验token就可以了 具体就是加上csrf_field
就可以了
对于第二种 我的想法就是直接给他报错好了 (233)
对于第三种 网上找了好多也没啥好的解决办法 大概就是做了简单的跳转处理 我觉得这样也可以哦,如果你有空可以把交互做的好一点 于是就用这种办法先做了下
本来准备直接动刀 Illuminate\Foundation\Http\Middleware\VerifyCsrfToken
这个类去做添加处理判断的 后来听了 mike 和 lee 童鞋的提醒还是回到 app/Http/Middleware/VerifyCsrfToken.php
来做更改(多谢提醒)【框架底层的东东尽量还是别动的好】
在app/Http/Middleware/VerifyCsrfToken.php
增加如下方法:
注意:需要引入
use Closure;
和use Illuminate\Session\TokenMismatchException;
我上面的那个errorss
是路由中配置的 具体的就是对应一个方法指向了一个404页面 具体的方法内容随便你喽不用直接模仿我这个 你可以做的更炫酷 更友好的提示页面耶可以
|
|
如果本地为了测试这个报错的话 需要更改本地配置文件中间的session时间,有可能会收不到redirect
返回带回的信息哦 因为他返回带的信息都是存在session中的 如果你设置的时间过短会读不到这个 with 的信息