CSRF 保護

介紹

Laravel 可以輕易地保護你的應用程式免受到跨網站偽造請求攻擊(CSRF)。跨網站偽造請求是一種惡意的攻擊,會偽造已認證的使用者執行未授權的指令。

Laravel 透過應用程式自動產生一個 CSRF「token」來管理每個活躍的使用者 session。這個 token 用於驗證已認證使用者是否實際向應用程式發出請求。

在你每次定義 HTML 表單的時候,應該在表單中插入隱藏的 CSRF token,這樣用於預防 CSRF 攻擊的中介層可以驗證表單請求。你可以使用 csrf_field 輔助函式來產生 token 到表單中:

<form method="POST" action="/profile">
     {{ csrf_field() }} 
    ...
</form>

包含在 web 中介層群組的 VerifyCsrfToken 中介層,會自動驗證表單請求的 token 是否與儲存在 session 的 token 一致。

CSRF Tokens 與 JavaScript

建構 JavaScript 應用程式的時候,可以用很便利的方式讓你的 JavaScript HTTP 函式庫也能自動附加 CSRF token 到每個對外的請求。預設上,resources/assets/js/bootstrap.js 檔案註冊了已寫入 csrf-token 屬性標籤值的 Axios HTTP 函式庫。如果你不要使用這個函式庫,則需要為應用程式手動設定此行為。

從 CSRF 保護中排除 URI

有些時候,你可能希望從 CSRF 保護範圍中忽略一組 URI。舉例來說,如果你正使用 Stripe 來處理付款且還使用他們的 webhook 系統,你會需要從 CSRF 保護範圍中忽略 Stripe 的處理路由,因為 Stripe 不會知道要發 CSRF token 給你的路由。

通常來說,你應該將這類型的路由放置於 web 中介層群組之外,是因為 RouteServiceProvider 會使用 web 中介層群組並應用在 routes/web.php 裡的全部路由。不過,你也可以在 VerifyCsrfToken 中介層中新增他們的 URI 到 $except 屬性來設置白名單:

<?php

namespace App\Http\Middleware;

use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware;

class VerifyCsrfToken extends Middleware
{
    /**
     * URI 將排除於 CSRF 驗證流程
     *
     * @var array
     */
    protected $except = [
        'stripe/*',
    ];
}

X-CSRF-TOKEN

除了把 CSRF token 作為 POST 參數來檢查外,VerifyCsrfToken 中介層也會檢查 X-CSRF-TOKEN 請求標頭。如範例所見,你可以將 token 存放在 HTML 的 meta 標籤裡:

<meta name="csrf-token" content=" {{ csrf_token() }} ">

然後,一旦你建好 meta 標籤,就能指示類似 jQuery 的函式庫自動新增 token 到每個請求標頭。這能為你的 AJAX 應用程式提供既簡單又便利的 CSRF 保護:

$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
    }
});

{tip} 預設上,resources/assets/js/bootstrap.js 檔案會使用 Axios HTTP 函式庫來註冊 csrf-token meta 標籤的值。如果你想使用這個函式庫,則需要為應用程式手動設定此行為。

X-XSRF-TOKEN

Laravel 會在每個由框架產生的回應中包含一組 XSRF-TOKEN cookie,並將當前的 CSRF token 儲存於此。你能使用 cookie 的值去設定 X-XSRF-TOKEN 的請求標頭。

之所以這個 cookie 能方便地被發送,主要是因為一些 JavaScript 框架和函式庫(像是 Angular 和 Axios)會自動將其值放入 X-XSRF-TOKEN 標頭。