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

# Laravel Fetch Metadata

> Sec-Fetch-* 헤더를 사용한 보안 미들웨어로, Laravel 앱을 CSRF 공격이나 크로스사이트 요청으로부터 보호합니다.

## 개요

[revolution/laravel-fetch-metadata](https://github.com/invokable/laravel-fetch-metadata)는 브라우저가 전송하는 `Sec-Fetch-*` HTTP 헤더를 검증하는 보안 미들웨어 패키지입니다. 요청의 발생원·모드·대상·사용자 조작 유무에 기반해 허용할 요청을 제어할 수 있습니다.

브라우저에 내장된 보안 기능을 활용함으로써, 정상 사용자의 경험을 해치지 않으면서도 부정한 오리진으로부터의 악의적인 요청을 방지할 수 있습니다.

<Info>
  Laravel 13에서는 CSRF 보호의 Origin 검증에 `Sec-Fetch-Site` 헤더가 사용되게 되었습니다. 자세한 내용은 [CSRF 보호](/ko/csrf)를 참조하세요.
</Info>

Fetch Metadata에 대한 자세한 사양은 [MDN 문서](https://developer.mozilla.org/ja/docs/Glossary/Fetch_metadata_request_header)를 참조하세요.

## 설치

```bash theme={null}
composer require revolution/laravel-fetch-metadata
```

### 미들웨어 별칭 등록

`bootstrap/app.php`에 미들웨어 별칭을 등록합니다.

```php theme={null}
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 문서](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Sec-Fetch-Site)를 참조하세요.

### SecFetchMode

`Sec-Fetch-Mode` 헤더는 요청의 모드를 나타냅니다. 기본값으로는 `navigate`와 `cors`를 허용합니다.

| 값             | 설명                       |
| ------------- | ------------------------ |
| `navigate`    | 링크 클릭이나 폼 전송 등의 내비게이션 요청 |
| `cors`        | CORS 요청                  |
| `no-cors`     | no-cors 요청               |
| `same-origin` | 동일 오리진 요청                |
| `websocket`   | WebSocket 접속 요청          |

자세한 내용은 [MDN 문서](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Sec-Fetch-Mode)를 참조하세요.

### SecFetchDest

`Sec-Fetch-Dest` 헤더는 요청의 대상 리소스 타입을 나타냅니다.

자세한 내용은 [MDN 문서](https://developer.mozilla.org/ja/docs/Web/HTTP/Headers/Sec-Fetch-Dest)를 참조하세요.

### SecFetchUser

`Sec-Fetch-User` 헤더는 요청이 사용자의 조작에 의해 개시되었는지 여부를 나타냅니다. 값은 `?1`(사용자 조작 있음)뿐입니다.

<Warning>
  `SecFetchUser` 미들웨어를 사용하면 검색 엔진 크롤러나 AI 에이전트도 차단됩니다. 인덱스가 필요한 공개 페이지에는 사용하지 마세요.
</Warning>

## 라우팅에서의 사용 예시

### 기본적인 사용

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

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

### 파라미터로 허용할 값을 지정

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

### 여러 파라미터 지정

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

### 별칭을 사용하지 않는 경우

```php theme={null}
use Revolution\FetchMetadata\Middleware\SecFetchSite;

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

### 여러 미들웨어 조합

```php theme={null}
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`에서 응답을 커스터마이즈할 수 있습니다.

```php theme={null}
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 보호](/ko/csrf)를 참조하세요.

<Info>
  최신 정보는 [GitHub 저장소](https://github.com/invokable/laravel-fetch-metadata)를 참조하세요.
</Info>


## Related topics

- [Laravel 12에서 13으로의 업그레이드 가이드](/ko/blog/upgrade-12-to-13.md)
- [Socialite - Laravel Bluesky](/ko/packages/laravel-bluesky/socialite.md)
- [Laravel MCP](/ko/mcp.md)
- [세션 컨텍스트와 필터링](/ko/packages/laravel-copilot-sdk/session-context.md)
- [세션 재개](/ko/packages/laravel-copilot-sdk/resume.md)
