[TOC]
:-: 
# 簡介
跨站請求偽造(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/assets/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')
}
});
~~~
# 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`,感興趣的同學可以去一窺究竟。
- 序言
- 新版特性
- 快速入門
- 升級指南
- 貢獻指南
- API文檔
- 安裝配置
- 目錄結構
- Homestead
- Valet
- 部署
- 核心概念
- 請求生命周期
- 服務容器
- 服務提供者
- 門面(Facades)
- 契約(Contracts)
- 框架基礎
- 路由
- 中間件
- CSRF 保護
- 控制器
- 請求
- 響應
- 視圖
- 生成 URL
- Session
- 驗證
- 錯誤處理
- 日志
- 前端開發
- Blade 模板
- 本地化
- 前端腳手架
- 編譯前端資源(Laravel Mix)
- 安全系列
- 登錄認證
- API 認證
- 授權
- 加密
- 哈希
- 重置密碼
- 進階系列
- Artisan 控制臺
- 集合
- 廣播
- 緩存
- 事件
- 文件存儲
- 輔助函數
- 郵件
- 通知
- 擴展包開發
- 隊列
- 任務調度
- 數據庫操作
- 快速入門
- 查詢構建器
- 分頁
- 遷移
- 數據填充
- Redis
- Eloquent ORM
- 快速入門
- 關聯關系
- 集合
- 訪問器 & 修改器
- API 資源類
- 序列化
- 應用測試
- 快速入門
- HTTP 測試
- 瀏覽器測試
- 數據庫測試
- 模擬
- 官方擴展包
- Cashier(訂閱支付解決方案)
- Envoy(遠程操作解決方案)
- Horizon(隊列系統解決方案)
- Passport(API 認證解決方案)
- Scout(全文搜索解決方案)
- Socialite(第三方登錄解決方案)
- 相關下載
- Laravel 5.6 中文文檔離線版
- Laravel 5.6 一鍵安裝包