[ Laravel 5.8 文件 ] 基礎元件 —— CSRF 保護
簡介
跨站請求偽造(CSRF)是一種通過偽裝授權使用者的請求來攻擊授信網站的惡意漏洞。
Laravel 通過自帶的 CSRF 保護中介軟體讓避免應用遭到跨站請求偽造攻擊變得簡單:Laravel 會自動為每一個被應用管理的有效使用者會話生成一個 CSRF “令牌”,然後將該令牌存放在 Session 中,該令牌用於驗證授權使用者和發起請求者是否是同一個人。
任何時候在 Laravel 應用中定義 HTML 表單,都需要在表單中引入 CSRF 令牌欄位,這樣 CSRF 保護中介軟體才能夠對請求進行驗證。要想生成包含 CSRF 令牌的隱藏輸入欄位,可以使用 Blade 指令 @csrf
:
<form method="POST" action="/profile"> @csrf ... </form>
中介軟體組 web
中的中介軟體 VerifyCsrfToken
會自動為我們驗證請求輸入的 token 值和 Session 中儲存的 token 是否一致,如果沒有傳遞該欄位或者傳遞過來的欄位值和 Session 中儲存的數值不一致,則會丟擲異常。
為了演示該功能,我們在 routes/web.php
中定義一組測試路由:
Route::get('form_without_csrf_token', function (){ return '<form method="POST" action="/hello_from_form"><button type="submit">提交</button></form>'; }); Route::get('form_with_csrf_token', function () { return '<form method="POST" action="/hello_from_form">' . csrf_field() . '<button type="submit">提交</button></form>'; }); Route::get('hello_from_form', function (){ return 'hello laravel!'; });
我們在瀏覽器中訪問 http://blog.test/form_without_csrf_token
並點選頁面上的提交按鈕時,頁面報錯,丟擲 MethodNotAllowedHttpException
異常,出現這個異常往往就是意味著沒有傳遞 CSRF 令牌欄位或者傳遞的令牌欄位不正確:
而當我們訪問 http://blog.test/form_csrf_token
並點選頁面上的提交按鈕時,頁面顯示正常。
注:CSRF 中介軟體只只作用於 routes/web.php
中定義的路由,因為該檔案下的路由分配了 web
中介軟體組,而 VerifyCsrfToken
位於 web
中介軟體組中。
CSRF 令牌 & JavaScript
構建 JavaScript 驅動的應用時,為方便起見,可以讓 JavaScript HTTP 庫自動在每個請求中新增 CSRF 令牌。預設情況下, resources/js/bootstrap.js
檔案會將 csrf-token
meta 標籤值註冊到 Axios HTTP 庫。如果你沒有使用這個庫,則需要手動在應用中配置該實現。
排除指定 URL 不做 CSRF 安全校驗
有時候我們需要從 CSRF 保護中介軟體中排除一些 URL,例如,如果你使用了第三方支付系統(如支付寶或微信支付)來處理支付並用到他們提供的回撥功能,這時候就需要從 Laravel 的 CSRF 保護中介軟體中排除回撥處理器路由,因為第三方支付系統並不知道要傳什麼 token 值給我們定義的路由。
通常我們需要將這種型別的路由放到檔案 routes/web.php
之外,比如 routes/api.php
。不過,如果必須要加到 routes/web.php
中的話,你也可以在 VerifyCsrfToken
中介軟體中將要排除的 URL 新增到 $except
屬性陣列:
<?php namespace App\Http\Middleware; use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware; class VerifyCsrfToken extends Middleware { /** * 從 CSRF 驗證中排除的 URL * * @var array */ protected $except = [ 'alipay/*', 'http://example.com/foo/bar', 'http://example.com/foo/*', ]; }
注:執行測試時 CSRF 中介軟體會自動禁止。
X-CSRF-Token
除了將 CSRF 令牌作為 POST 引數進行驗證外,還可以通過設定 X-CSRF-Token
請求頭來實現驗證, VerifyCsrfToken
中介軟體會檢查 X-CSRF-TOKEN
請求頭。實現方式如下,首先建立一個 meta
標籤並將令牌儲存到該 meta
標籤:
<meta name="csrf-token" content="{{ csrf_token() }}">
然後在 js 庫(如 jQuery)中新增該令牌到所有請求頭,這為基於 AJAX 的請求提供了簡單、方便的方式來避免 CSRF 攻擊:
$.ajaxSetup({ headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } });
注:預設情況下, resources/js/bootstrap.js
檔案會將 csrf-token
meta 標籤值新增到 Axios HTTP 庫,如果你沒有使用這個庫,則需要手動配置應用的行為。
X-XSRF-Token
Laravel 還會將 CSRF 令牌儲存到名為 XSRF-TOKEN
的 Cookie 中,你可以使用該 Cookie 值來設定 X-XSRF-TOKEN
請求頭。
一些 JavaScript 框架,比如 Angular 和 Axios,會為你自動進行上述設定,基本上你不太需要手動設定這個值。
最後, VerifyCsrfToken
中介軟體框架底層實現原始碼位於 vendor/laravel/framework/src/Illuminate/Foundation/Http/Middleware/VerifyCsrfToken.php
,感興趣的同學可以去一窺究竟。