產(chǎn)生VerifyCsrfToken的原因主要是為了防止跨站偽造請(qǐng)求。給每個(gè)瀏覽器產(chǎn)生一個(gè)不同的VerifyCsrfToken,是為了保證請(qǐng)求的合法性魏滚。
當(dāng)啟用VerifyCsrfToken中間件以后,表單請(qǐng)求,異步請(qǐng)求或者socket請(qǐng)求昏名,都必須帶上用戶唯一的VerifyCsrfToken給后臺(tái)進(jìn)行驗(yàn)證。
其中阵面,原理如下轻局。
一、加載VerifyCsrfToken中間件
(1)當(dāng)路由中聲明是用默認(rèn)的web中間件以后样刷,在web中間件中仑扑,會(huì)聲明使用VerifyCsrfToken中間件。其中置鼻,關(guān)于web中間件和路由之前的關(guān)系镇饮,可以點(diǎn)擊我寫(xiě)的《laravel 5.3 5.4 5.5 中 route 路由源碼分析》和《laravel 5.3 5.4 5.5 中 route 路由 分割實(shí)現(xiàn)方式》這兩篇文章查看。
(2)初始化默認(rèn)中間件箕母。
入口文件:public/index.php
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
初始化系統(tǒng)Kernel類储藐,然后默認(rèn)初始化/app/Http/Kernel類
在/app/Http/Kernel中,指明了web中間件組使用VerifyCsrfToken中間件嘶是。所以路由中指明使用默認(rèn)的web中間件钙勃,就要通過(guò)VerifyCsrfToken中間件驗(yàn)證。
'web' => [
....
? ? \App\Http\Middleware\VerifyCsrfToken::class,
],
二聂喇、生成VerifyCsrfToken
核心副主函數(shù)中:vendor/laravel/framework/src/Illuminate/Foundation/helpers.php
通過(guò) function csrf_token()生成VerifyCsrfToken
生成步驟大致是在vendor/laravel/framework/src/Illuminate/Session/Store.php中辖源,
通過(guò)
public function regenerateToken()
{
? ? $this->put('_token', Str::random(40));
}
生成token
通過(guò)
public function token()
{
? ? return $this->get('_token');
}
獲取token
調(diào)用VerifyCsrfToken
直接使用csrf_token()輔助函數(shù)即可。
三授帕、提交VerifyCsrfToken
(1)首先同木,laravel向外開(kāi)放配置項(xiàng),允許指定的路由可以不經(jīng)過(guò)VerifyCsrfToken的驗(yàn)證跛十。
在app/Http/Middleware/VerifyCsrfToken.php中
protected $except = [
? ? //
];
指明所要忽略使用VerifyCsrfToken驗(yàn)證的路由即可彤路。
(2)識(shí)別請(qǐng)求
入口中間件類:vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php
按照中間件的規(guī)則,處理其中的handle方法芥映。
if (
? ? $this->isReading($request) ||? ? ? ? ?//排除只讀請(qǐng)求
? ? $this->runningUnitTests() ||? ? ? ? ? ?//排除單元測(cè)試請(qǐng)求
? ? $this->inExceptArray($request) ||? //排除在開(kāi)放的配置中的不需要驗(yàn)證的路由
? ? $this->tokensMatch($request)? ? ? //處理token洲尊,詳看步驟(3)
) {
? ? return $this->addCookieToResponse($request, $next($request));??
?// token驗(yàn)證通過(guò)以后远豺,給用戶生成cookie
}
(3)處理token
protected function tokensMatch($request)
{
? ? $token = $this->getTokenFromRequest($request);??//獲取提交過(guò)來(lái)的VerifyCsrfToken,詳細(xì)看步驟(4)
? ? return is_string($request->session()->token()) &&
? ? ? ? ? is_string($token) &&
? ? ? ? ? hash_equals($request->session()->token(), $token);
? //檢查token的合法性坞嘀,判斷提交過(guò)來(lái)的token跟緩存中的token是否相等躯护。
}
(4)獲取提交的VerifyCsrfToken
protected function getTokenFromRequest($request)
{
? ? $token = $request->input('_token') ?: $request->header('X-CSRF-TOKEN'); //表單和請(qǐng)求頭提交的token
? ? if (! $token && $header = $request->header('X-XSRF-TOKEN')) { //處理ajax提交的token
? ? ? ? $token = $this->encrypter->decrypt($header);
}
? ? return $token;
}
四、總結(jié)流程丽涩,通過(guò)VerifyCsrfToken防止夸張棺滞。
VerifyCsrfToken作用是防止用戶瀏覽器被挾持,通過(guò)用戶瀏覽器矢渊,提交非法的cookie來(lái)非法獲取信息继准。
有VerifyCsrfToken以后,VerifyCsrfToken生成在客戶端矮男,客戶端提交生成的VerifyCsrfToken到后端服務(wù)器驗(yàn)證移必,驗(yàn)證VerifyCsrfToken跟服務(wù)器中的VerifyCsrfToken相同,則證明不存在夸張毡鉴,否則存在夸張危險(xiǎn)崔泵。