前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >laravel的csrf token 的了解及使用

laravel的csrf token 的了解及使用

作者头像
lin_zone
发布2018-08-15 11:16:31
3.7K0
发布2018-08-15 11:16:31
举报
文章被收录于专栏:LIN_ZONELIN_ZONELIN_ZONE

之前在项目中因为没有弄清楚csrf token的使用,导致发请求的话,一直请求失败,今天就一起来看一下csrf的一些东西。

 1.Cross-site request forgery 跨站请求伪造,也被称为 “one click attack” 或者 session riding,通常缩写为 CSRF 或者 XSRF,是一种对网站的恶意利用。CSRF 则通过伪装来自受信任用户的请求来利用受信任的网站。

2.从字面意思就可以理解:当你访问 fuck.com 黑客页面的时候,页面上放了一个按钮或者一个表单,URL/action 为 http://you.com/delete-myself,这样引导或迫使甚至伪造用户触发按钮或表单。在浏览器发出 GET 或 POST 请求的时候,它会带上 you.com 的 cookie,如果网站没有做 CSRF 防御措施,那么这次请求在 you.com 看来会是完全合法的,这样就会对 you.com 的数据产生破坏。

3.第三方恶意网站也是可以构造post请求并提交至被攻击网站的,所以POST方式提交只是提高了攻击的门槛而已,无法防范CSRF攻击,所以对post也要进行防范

关于csrf更多的请参考 https://segmentfault.com/q/1010000000713614  https://www.ibm.com/developerworks/cn/web/1102_niugang_csrf/

在laravel中为了防止csrf 攻击,设计了  csrf token

laravel默认是开启了csrf token 验证的,关闭这个功能的方法:

(1)打开文件:app\Http\Kernel.php

  把这行注释掉:‘App\Http\Middleware\VerifyCsrfToken’

(2)打开文件 app\Http\Middleware\VerifyCsrfToken.php

    修改handle方法为:   

1  public function handle($request, Closure $next)
2     {
3         // 使用CSRF
4         //return parent::handle($request, $next);
5         // 禁用CSRF
6         return $next($request);
7     }

csrf的使用:

(1)在html的代码中加入:

1 <input type="hidden" name="_token" value="{{ csrf_token() }}" />

(2)使用cookie 方式 ,将app\Http\Middleware\VerifyCsrfToken.php修改为:

 1 <?php namespace App\Http\Middleware;
 2 
 3 use Closure;
 4 use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
 5 
 6 class VerifyCsrfToken extends BaseVerifier {
 7 
 8     /**
 9      * Handle an incoming request.
10      *
11      * @param  \Illuminate\Http\Request  $request
12      * @param  \Closure  $next
13      * @return mixed
14      */
15     public function handle($request, Closure $next)
16     {
17         return parent::addCookieToResponse($request, $next($request));
18     }
19 
20 }

使用cookie方法就不用在每个页面都加入这个input 的 hidden 标签

还可以部分使用csrf检测部分不使用。

注:本文从laravel的csrf token开始到此参考:http://blog.csdn.net/proud2005/article/details/49995389

关于  laravel 的 csrf 保护更多的内容请参考 laravel学院文档:http://laravelacademy.org/post/6742.html

下面说说我们那个项目中的关于csrf token的使用:

在我的另一篇文章中也提到了我们那个项目中的使用过程

在中间件VerifyCsrfToken.php中修改内容为:
 1 protected function tokensMatch($request)
 2 {
 3     // If request is an ajax request, then check to see if token matches token provider in
 4     // the header. This way, we can use CSRF protection in ajax requests also.
 5     $token = $request->ajax() ? $request->header('X-CSRF-TOKEN') : $request->input('_token');
 6     return $request->session()->token() == $token;
 7 }
 8 
 9 public function handle($request,\Closure $next){
10     //todo:需要在添加了登录验证之后,取消
11    //这样是在post请求的时候不进行csrf token验证
12     if($request->method() == 'POST')
13     {
14         return $next($request);
15     }
16     
17     return parent::handle($request,$next);
18 }
然后在vue中的bootstrap.js中的引入的axios的位置添加
 1 window.axios.defaults.headers.common = { 2 'X-CSRF-TOKEN': document.querySelector('meta[name="X-CSRF-TOKEN"]').content, 3 'X-Requested-With': 'XMLHttpRequest' 4 }; 

在index.blade.php中添加
 1 <meta name="X-CSRF-TOKEN" content="{{csrf_token()}}"> 

上面的代码都好理解,就是获取到 csrf_token令牌,然后提交,再经过中间件验证即可

下面重点来说一下 VerifyCsrfToken.php中间件

中间件的内容最开始应该只有一个 handle函数:这个是所有的都进行csrf token验证

1  public function handle($request,\Closure $next){
2         return parent::handle($request,$next);
3     }

现在项目中的这个中间件的内容

 1 <?php
 2 
 3 namespace App\Http\Middleware;
 4 
 5 use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as BaseVerifier;
 6 
 7 class VerifyCsrfToken extends BaseVerifier
 8 {
 9     /**
10      * The URIs that should be excluded from CSRF verification.
11      *
12      * @var array
13      */
14     protected $except = [
15         //
16     ];
17 //    protected $except = [
18 //
19 //        '/classroom_upload',
20 //        'wk_upload',
21 //        'wechat',
22 //    ];
23     protected function tokensMatch($request)
24     {
25         // If request is an ajax request, then check to see if token matches token provider in
26         // the header. This way, we can use CSRF protection in ajax requests also.
27         $token = $request->ajax() ? $request->header('X-CSRF-TOKEN') : $request->input('_token');
28         return $request->session()->token() == $token;
29     }
30 
31 
32     public function handle($request,\Closure $next){
33         //todo:需要在添加了登录验证之后,取消
34         if($request->method() == 'POST')
35         {
36             return $next($request);
37         }
38         
39         return parent::handle($request,$next);
40     }
41 }

我们来看一下 VerifyCsrfToken.php的源码             Illuminate\Foundation\Http\Middleware\VerifyCsrfToken.php;

  1 <?php
  2 
  3 namespace Illuminate\Foundation\Http\Middleware;
  4 
  5 use Closure;
  6 use Carbon\Carbon;
  7 use Illuminate\Foundation\Application;
  8 use Symfony\Component\HttpFoundation\Cookie;
  9 use Illuminate\Contracts\Encryption\Encrypter;
 10 use Illuminate\Session\TokenMismatchException;
 11 
 12 class VerifyCsrfToken
 13 {
 14     /**
 15      * The application instance.
 16      *
 17      * @var \Illuminate\Foundation\Application
 18      */
 19     protected $app;
 20 
 21     /**
 22      * The encrypter implementation.
 23      *
 24      * @var \Illuminate\Contracts\Encryption\Encrypter
 25      */
 26     protected $encrypter;
 27 
 28     /**
 29      * The URIs that should be excluded from CSRF verification.
 30      *
 31      * @var array
 32      */
 33     protected $except = [];
 34 
 35     /**
 36      * Create a new middleware instance.
 37      *
 38      * @param  \Illuminate\Foundation\Application  $app
 39      * @param  \Illuminate\Contracts\Encryption\Encrypter  $encrypter
 40      * @return void
 41      */
 42     public function __construct(Application $app, Encrypter $encrypter)
 43     {
 44         $this->app = $app;
 45         $this->encrypter = $encrypter;
 46     }
 47 
 48     /**
 49      * Handle an incoming request.
 50      *
 51      * @param  \Illuminate\Http\Request  $request
 52      * @param  \Closure  $next
 53      * @return mixed
 54      *
 55      * @throws \Illuminate\Session\TokenMismatchException
 56      */
 57     public function handle($request, Closure $next)
 58     {
 59         if (
 60             $this->isReading($request) ||
 61             $this->runningUnitTests() ||
 62             $this->inExceptArray($request) ||
 63             $this->tokensMatch($request)
 64         ) {
 65             return $this->addCookieToResponse($request, $next($request));
 66         }
 67 
 68         throw new TokenMismatchException;
 69     }
 70 
 71     /**
 72      * Determine if the HTTP request uses a ‘read’ verb.
 73      *
 74      * @param  \Illuminate\Http\Request  $request
 75      * @return bool
 76      */
 77     protected function isReading($request)
 78     {
 79         return in_array($request->method(), ['HEAD', 'GET', 'OPTIONS']);
 80     }
 81 
 82     /**
 83      * Determine if the application is running unit tests.
 84      *
 85      * @return bool
 86      */
 87     protected function runningUnitTests()
 88     {
 89         return $this->app->runningInConsole() && $this->app->runningUnitTests();
 90     }
 91 
 92     /**
 93      * Determine if the request has a URI that should pass through CSRF verification.
 94      *
 95      * @param  \Illuminate\Http\Request  $request
 96      * @return bool
 97      */
 98     protected function inExceptArray($request)
 99     {
100         foreach ($this->except as $except) {
101             if ($except !== '/') {
102                 $except = trim($except, '/');
103             }
104 
105             if ($request->is($except)) {
106                 return true;
107             }
108         }
109 
110         return false;
111     }
112 
113     /**
114      * Determine if the session and input CSRF tokens match.
115      *
116      * @param  \Illuminate\Http\Request  $request
117      * @return bool
118      */
119     protected function tokensMatch($request)
120     {
121         $token = $this->getTokenFromRequest($request);
122 
123         return is_string($request->session()->token()) &&
124                is_string($token) &&
125                hash_equals($request->session()->token(), $token);
126     }
127 
128     /**
129      * Get the CSRF token from the request.
130      *
131      * @param  \Illuminate\Http\Request  $request
132      * @return string
133      */
134     protected function getTokenFromRequest($request)
135     {
136         $token = $request->input('_token') ?: $request->header('X-CSRF-TOKEN');
137 
138         if (! $token && $header = $request->header('X-XSRF-TOKEN')) {
139             $token = $this->encrypter->decrypt($header);
140         }
141 
142         return $token;
143     }
144 
145     /**
146      * Add the CSRF token to the response cookies.
147      *
148      * @param  \Illuminate\Http\Request  $request
149      * @param  \Symfony\Component\HttpFoundation\Response  $response
150      * @return \Symfony\Component\HttpFoundation\Response
151      */
152     protected function addCookieToResponse($request, $response)
153     {
154         $config = config('session');
155 
156         $response->headers->setCookie(
157             new Cookie(
158                 'XSRF-TOKEN', $request->session()->token(), Carbon::now()->getTimestamp() + 60 * $config['lifetime'],
159                 $config['path'], $config['domain'], $config['secure'], false
160             )
161         );
162 
163         return $response;
164     }
165 }

其中app下面的VerifyCsrfToken中间件是继承源码中的那个VerifyCsrfToken类

我们项目中重写了tokensMatch方法,然后调父类的handle的时候,父类中使用的是this调用tokensMatch的,个人感觉应该最后有用的是我们重写的这个方法,如果是ajax请求的话,我们就检测$request->header('X-CSRF-TOKEN')与session中的token是否一样 否则的话,就检测 $request->input('_token')与session中的token是否一样。

本人对laravel的原理还不太了解,上面的内容如果有什么错误的话,欢迎指教。

如需转载请注明:

本文出处:http://www.cnblogs.com/zhuchenglin/p/7723997.html

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-10-24 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
消息队列 TDMQ
消息队列 TDMQ (Tencent Distributed Message Queue)是腾讯基于 Apache Pulsar 自研的一个云原生消息中间件系列,其中包含兼容Pulsar、RabbitMQ、RocketMQ 等协议的消息队列子产品,得益于其底层计算与存储分离的架构,TDMQ 具备良好的弹性伸缩以及故障恢复能力。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档