> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# CSRF 保護

> 說明 CSRF 攻擊的原理，以及 Laravel 13 透過 Origin 驗證與 token 驗證進行防禦的方式。

## 簡介

CSRF（Cross-Site Request Forgery）是一種偽裝成已登入使用者、藉此發出非預期請求的攻擊手法。

例如，假設你的應用程式中有一個 `POST /user/email` 可接收 email 變更請求。攻擊者若在另一站點放置能自動送出此 URL 表單的程式碼，使用者可能在不知情下被變更 email。

在 Laravel 13 中，CSRF 保護透過內含於 `web` 中介軟體群組的機制而預設啟用。

## 防禦 CSRF 攻擊

Laravel 的 `PreventRequestForgery` 中介軟體以 2 層防禦阻擋 CSRF：

1. **Origin 驗證**（`Sec-Fetch-Site` 標頭）
2. **Token 驗證**（每個 session 的 CSRF token）

會先檢查 Origin，若無法判斷或失敗時再退回到 token 驗證。

## Origin 驗證

Laravel 會先檢查 `Sec-Fetch-Site` 判斷請求是否來自相同 Origin。此在 HTTPS 環境下特別有效。

若 Origin 驗證通過，該請求即被允許。若未通過，則會如同以往地執行 CSRF token 驗證。

<Warning>
  `Sec-Fetch-Site` 是為 HTTPS 連線設計的。在 HTTP 環境中 Origin 驗證無法運作，主要防禦仍會是 token 驗證。
</Warning>

### Origin-only 模式

也可以停用退回至 token 驗證，只以 Origin 驗證進行判斷。

```php theme={null}
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withMiddleware(function (Middleware $middleware): void {
        $middleware->preventRequestForgery(originOnly: true);
    });
```

在 Origin-only 模式下，Origin 驗證失敗的請求會回傳 `403` 而非 `419`。

若要在子網域間允許 same-site 請求，可以設定 `allowSameSite`。

```php theme={null}
$middleware->preventRequestForgery(allowSameSite: true);
```

## Token 驗證

Laravel 會為每個 session 生成 CSRF token，可透過 `csrf_token()` 或 session 取得。

```php theme={null}
use Illuminate\Http\Request;

Route::get('/token', function (Request $request) {
    $tokenFromSession = $request->session()->token();
    $tokenFromHelper = csrf_token();
});
```

在 `web` 路由中建立 `POST`、`PUT`、`PATCH`、`DELETE` 表單時，請務必包含 `@csrf`。

```blade theme={null}
<form method="POST" action="/profile">
    @csrf

    <!-- 等同的 hidden input -->
    <input type="hidden" name="_token" value="{{ csrf_token() }}" />
</form>
```

## 排除特定 URI

像是 Stripe 的 Webhook 這種來自外部服務的請求，可能需要將特定 URI 排除於 CSRF 保護之外。

```php theme={null}
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withMiddleware(function (Middleware $middleware): void {
        $middleware->preventRequestForgery(except: [
            'stripe/*',
            'http://example.com/foo/bar',
            'http://example.com/foo/*',
        ]);
    });
```

<Info>
  盡可能將 Webhook 路由放在 `web` 中介軟體群組之外，並將排除設定降到最少。
</Info>

## X-CSRF-TOKEN 標頭

Laravel 不僅會驗證表單的 `_token`，也會檢查 `X-CSRF-TOKEN` 標頭。

先在 meta 標籤中輸出 token。

```blade theme={null}
<meta name="csrf-token" content="{{ csrf_token() }}">
```

再將該值加入 AJAX 請求標頭。

```js theme={null}
$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': document
            .querySelector('meta[name="csrf-token"]')
            .getAttribute('content'),
    },
});
```

## X-XSRF-TOKEN 標頭

Laravel 還會傳送加密的 `XSRF-TOKEN` Cookie。Axios 或 Angular 在同源請求時可自動將此值設為 `X-XSRF-TOKEN` 標頭。

因此在 SPA 或 AJAX 實作中，某些情況下不必手動設定標頭，CSRF 保護就已生效。

## SPA 中的注意事項

當 SPA 以 Laravel 作為 API 後端時，需先取得 CSRF Cookie，才能送出登入請求。

```js theme={null}
await axios.get('/sanctum/csrf-cookie');
await axios.post('/login', {
    email: 'user@example.com',
    password: 'password',
});
```

詳細請參閱 [Sanctum](/zh-TW/sanctum)。


## Related topics

- [Blade 模板](/zh-TW/blade.md)
- [Laravel Fetch Metadata](/zh-TW/packages/laravel-fetch-metadata.md)
- [2026 年 3 月 Laravel 更新](/zh-TW/blog/changelog/202603.md)
- [中介軟體](/zh-TW/middleware.md)
- [HTTP 用戶端](/zh-TW/http-client.md)
