以前在項目中由於沒有弄清楚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的原理還不太瞭解,上面的內容若是有什麼錯誤的話,歡迎指教。
如需轉載請註明: