Laravel上實(shí)現(xiàn)CSRF保護(hù)

環(huán)境

Laravel5.4

什么是CSRF?

維基百科的解釋如下:
跨站請(qǐng)求偽造(英語:Cross-site request forgery),也被稱為 one-click attack 或者 session riding,通常縮寫為 CSRF 或者 XSRF, 是一種挾制用戶在當(dāng)前已登錄的Web應(yīng)用程序上執(zhí)行非本意的操作的攻擊方法。[1] 跟跨網(wǎng)站腳本(XSS)相比,XSS 利用的是用戶對(duì)指定網(wǎng)站的信任,CSRF 利用的是網(wǎng)站對(duì)用戶網(wǎng)頁瀏覽器的信任。

那是誰利用了“網(wǎng)站對(duì)用戶網(wǎng)頁瀏覽器的任信”?可能是駭客,也可能是機(jī)器人,還可能是沒那么友善的用戶。

因此,我們有必要做好CSRF的保護(hù)。

在Laravel上如何實(shí)現(xiàn)CSRF保護(hù)?

開啟web.php路由中間件的CSRF保護(hù)

vi app/Http/Kernel.php

/**
 * The application's route middleware groups.
 *
 * @var array
 */
protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\VerifyCsrfToken::class,
    ],
];

開啟axios自動(dòng)在ajax請(qǐng)求時(shí)發(fā)送X-CSRF-TOKEN http header

vi resources/assets/js/bootstrap.js

window.axios.defaults.headers.common['X-CSRF-TOKEN'] = window.Laravel.csrfToken;
window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';

在layout文件(如master.blade.php)或任何需要CSRF保護(hù)的blade模板文件設(shè)置csrf token

  • 在head處設(shè)置meta
<meta name="csrf-token" content="{{ csrf_token() }}" />
  • 在body的script標(biāo)簽里設(shè)置window.Laravel.csrfToken
window.Laravel = {
    csrfToken: '{{ csrf_token() }}'
};
  • 在body的script標(biāo)簽里設(shè)置$.ajaxSetup(為以后要用到的Ajax請(qǐng)求設(shè)置默認(rèn)的值)
$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});
  • 在需要直接提交(非ajax提交)的form標(biāo)簽里,設(shè)置_token
{{ csrf_field() }}

該模板標(biāo)簽會(huì)被blade模板語言編譯成,示例:

<input type="hidden" name="_token" value="5XioxfXUeJZfypAryNZ53SwTHbhjwIv0iqvrvBqa">

至此,CSRF保護(hù)就設(shè)置完成了。
但,我有個(gè)疑問,首次打開該網(wǎng)站的頁面(GET請(qǐng)求),是沒有_token、X-CSRF-TOKEN和X-XSRF-Token的,
而web.php路由中間件CSRF保護(hù)會(huì)驗(yàn)證所有請(qǐng)求,那豈不是會(huì)打不開該頁面?而事實(shí)上是可以打開的,于是,我找到了如下Laravel源碼:
Illuminate\Foundation\Http\Middleware\VerifyCsrfToken:

/**
 * Handle an incoming request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Closure  $next
 * @return mixed
 *
 * @throws \Illuminate\Session\TokenMismatchException
 */
public function handle($request, Closure $next)
{
    if (
        $this->isReading($request) ||
        $this->runningUnitTests() ||
        $this->inExceptArray($request) ||
        $this->tokensMatch($request)
    ) {
        return $this->addCookieToResponse($request, $next($request));
    }

    throw new TokenMismatchException;
}

/**
 * Determine if the HTTP request uses a ‘read’ verb.
 *
 * @param  \Illuminate\Http\Request  $request
 * @return bool
 */
protected function isReading($request)
{
    return in_array($request->method(), ['HEAD', 'GET', 'OPTIONS']);
}

/**
 * Add the CSRF token to the response cookies.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Symfony\Component\HttpFoundation\Response  $response
 * @return \Symfony\Component\HttpFoundation\Response
 */
protected function addCookieToResponse($request, $response)
{
    $config = config('session');

    $response->headers->setCookie(
        new Cookie(
            'XSRF-TOKEN', $request->session()->token(), Carbon::now()->getTimestamp() + 60 * $config['lifetime'],
            $config['path'], $config['domain'], $config['secure'], false
        )
    );

    return $response;
}

意思是,如果請(qǐng)求方式為HEAD、GET和OPTIONS,則發(fā)送名為XSRF-TOKEN的cookie,而不作CSRF驗(yàn)證。

完!如果認(rèn)為有用,可以考慮以贊賞的方式告訴我哦。

參考資料

-跨站請(qǐng)求偽造:
https://zh.wikipedia.org/wiki/跨站請(qǐng)求偽造

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容