跳转到主要内容

概览

revolution/laravel-fetch-metadata 是一个用于校验浏览器发送的 Sec-Fetch-* HTTP header 的安全中间件包。你可以根据请求的发起来源、模式、目标以及是否由用户操作触发,来控制允许通过的请求。 借助浏览器内建的安全能力,可以在不影响正常用户体验的前提下,阻止来自恶意来源的非法请求。
在 Laravel 13 中,CSRF 保护的 Origin 校验开始使用 Sec-Fetch-Site header。详情请参考 CSRF 保护
关于 Fetch Metadata 的详细规范,请参考 MDN 文档

安装

composer require revolution/laravel-fetch-metadata

注册中间件别名

bootstrap/app.php 中注册中间件别名。
use Illuminate\Foundation\Configuration\Middleware;
use Revolution\FetchMetadata\Middleware\SecFetchSite;
use Revolution\FetchMetadata\Middleware\SecFetchMode;
use Revolution\FetchMetadata\Middleware\SecFetchDest;
use Revolution\FetchMetadata\Middleware\SecFetchUser;

->withMiddleware(function (Middleware $middleware) {
    $middleware->alias([
        'sec-fetch-site' => SecFetchSite::class,
        'sec-fetch-mode' => SecFetchMode::class,
        'sec-fetch-dest' => SecFetchDest::class,
        'sec-fetch-user' => SecFetchUser::class,
    ]);
})
你也可以只使用其中的一部分中间件。别名可以任意修改。

中间件说明

SecFetchSite

Sec-Fetch-Site header 表示请求的发起来源与目标 origin 之间的关系。默认只允许 same-originnone(直接访问)。
说明
same-origin来自同一 origin 的请求
same-site来自同一 site(如子域名)的请求
cross-site来自不同 site 的请求
none用户直接输入 URL 等由导航发起的请求
详情请参考 MDN 文档

SecFetchMode

Sec-Fetch-Mode header 表示请求的模式。默认允许 navigatecors
说明
navigate由链接点击、表单提交等发起的导航请求
corsCORS 请求
no-corsno-cors 请求
same-origin同 origin 请求
websocketWebSocket 连接请求
详情请参考 MDN 文档

SecFetchDest

Sec-Fetch-Dest header 表示请求目标资源的类型。 详情请参考 MDN 文档

SecFetchUser

Sec-Fetch-User header 表示请求是否由用户操作触发。值只有 ?1(有用户操作)。
使用 SecFetchUser 中间件会同时拦截搜索引擎爬虫和 AI agent。请不要用在需要被索引的公开页面上。

在路由中的使用示例

基本用法

use Illuminate\Support\Facades\Route;
use Illuminate\Http\Request;

Route::post('user/update-password', function (Request $request) {
    //
})->middleware('sec-fetch-site');

通过参数指定允许值

Route::post('user/update-password', function (Request $request) {
    //
})->middleware('sec-fetch-site:cross-site');

指定多个参数

Route::post('user/update-password', function (Request $request) {
    //
})->middleware('sec-fetch-site:same-origin,cross-site');

不使用别名的情况

use Revolution\FetchMetadata\Middleware\SecFetchSite;

Route::post('user/update-password', function (Request $request) {
    //
})->middleware(SecFetchSite::class.':same-origin,cross-site');

组合多个中间件

Route::post('user/update-profile', function (Request $request) {
    //
})->middleware(['sec-fetch-site:same-origin', 'sec-fetch-mode:navigate']);

错误处理

Sec-Fetch-* header 的值不合法时,会抛出 Symfony\Component\HttpKernel\Exception\BadRequestHttpException 可以在 bootstrap/app.php 中自定义响应。
use Illuminate\Http\Request;
use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;

->withExceptions(function (Exceptions $exceptions) {
    $exceptions->render(function (BadRequestHttpException $e, Request $request) {
        if ($request->expectsJson()) {
            return response()->json([
                'message' => $e->getMessage(),
            ], 400);
        }
    });
})

与 CSRF 保护的关系

在 Laravel 13 中,PreventRequestForgery 中间件作为 CSRF 保护的第一步,会通过 Sec-Fetch-Site header 进行 Origin 校验。本包在更细粒度上进一步利用 Fetch Metadata header,可以进一步增强应用的安全性。 详情请参考 CSRF 保护
最新信息请参考 GitHub 仓库
最后修改于 2026年7月13日