laravel的csrf token 的瞭解及使用

以前在項目中由於沒有弄清楚csrf token的使用,致使發請求的話,一直請求失敗,今天就一塊兒來看一下csrf的一些東西。php

 1.Cross-site request forgery 跨站請求僞造,也被稱爲 「one click attack」 或者 session riding,一般縮寫爲 CSRF 或者 XSRF,是一種對網站的惡意利用。CSRF 則經過假裝來自受信任用戶的請求來利用受信任的網站。html

2.從字面意思就能夠理解:當你訪問 fuck.com 黑客頁面的時候,頁面上放了一個按鈕或者一個表單,URL/action 爲 http://you.com/delete-myself,這樣引導或迫使甚至僞造用戶觸發按鈕或表單。在瀏覽器發出 GET 或 POST 請求的時候,它會帶上 you.com 的 cookie,若是網站沒有作 CSRF 防護措施,那麼此次請求在 you.com 看來會是徹底合法的,這樣就會對 you.com 的數據產生破壞。vue

3.第三方惡意網站也是能夠構造post請求並提交至被攻擊網站的,因此POST方式提交只是提升了攻擊的門檻而已,沒法防範CSRF攻擊,因此對post也要進行防範ios

關於csrf更多的請參考 https://segmentfault.com/q/1010000000713614  https://www.ibm.com/developerworks/cn/web/1102_niugang_csrf/laravel

 

在laravel中爲了防止csrf 攻擊,設計了  csrf tokenweb

laravel默認是開啓了csrf token 驗證的,關閉這個功能的方法:ajax

(1)打開文件:app\Http\Kernel.phpbootstrap

  把這行註釋掉:‘App\Http\Middleware\VerifyCsrfToken’axios

(2)打開文件 app\Http\Middleware\VerifyCsrfToken.phpsegmentfault

    修改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

相關文章
相關標籤/搜索