revolution/laravel-fetch-metadata는 브라우저가 전송하는 Sec-Fetch-* HTTP 헤더를 검증하는 보안 미들웨어 패키지입니다. 요청의 발생원·모드·대상·사용자 조작 유무에 기반해 허용할 요청을 제어할 수 있습니다.
브라우저에 내장된 보안 기능을 활용함으로써, 정상 사용자의 경험을 해치지 않으면서도 부정한 오리진으로부터의 악의적인 요청을 방지할 수 있습니다.
Laravel 13에서는 CSRF 보호의 Origin 검증에 Sec-Fetch-Site 헤더가 사용되게 되었습니다. 자세한 내용은 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 헤더는 요청의 발생원과 타깃 오리진의 관계를 나타냅니다. 기본값으로는 same-origin과 none(직접 접근)만 허용합니다.
| 값 | 설명 |
|---|
same-origin | 동일 오리진에서의 요청 |
same-site | 서브도메인 등 동일 사이트에서의 요청 |
cross-site | 다른 사이트에서의 요청 |
none | 사용자가 직접 URL을 입력하는 등 내비게이션 시작 요청 |
자세한 내용은 MDN 문서를 참조하세요.
SecFetchMode
Sec-Fetch-Mode 헤더는 요청의 모드를 나타냅니다. 기본값으로는 navigate와 cors를 허용합니다.
| 값 | 설명 |
|---|
navigate | 링크 클릭이나 폼 전송 등의 내비게이션 요청 |
cors | CORS 요청 |
no-cors | no-cors 요청 |
same-origin | 동일 오리진 요청 |
websocket | WebSocket 접속 요청 |
자세한 내용은 MDN 문서를 참조하세요.
SecFetchDest
Sec-Fetch-Dest 헤더는 요청의 대상 리소스 타입을 나타냅니다.
자세한 내용은 MDN 문서를 참조하세요.
SecFetchUser
Sec-Fetch-User 헤더는 요청이 사용자의 조작에 의해 개시되었는지 여부를 나타냅니다. 값은 ?1(사용자 조작 있음)뿐입니다.
SecFetchUser 미들웨어를 사용하면 검색 엔진 크롤러나 AI 에이전트도 차단됩니다. 인덱스가 필요한 공개 페이지에는 사용하지 마세요.
라우팅에서의 사용 예시
기본적인 사용
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-* 헤더의 값이 부정한 경우, Symfony\Component\HttpKernel\Exception\BadRequestHttpException이 throw됩니다.
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 헤더에 의한 Origin 검증을 수행하게 되었습니다. 이 패키지는 나아가 더 세밀한 단위로 Fetch Metadata 헤더를 활용하여, 애플리케이션의 보안을 강화할 수 있습니다.
자세한 내용은 CSRF 보호를 참조하세요.