본문 바로가기

CSRF 보호

번역일: 2026년 6월 20일

CSRF 보호

소개

CSRF(Cross-Site Request Forgery)는 인증된 사용자의 권한을 도용해 의도치 않은 요청을 서버에 보내는 공격 기법입니다. Laravel은 이러한 CSRF 공격으로부터 애플리케이션을 쉽게 보호할 수 있는 기능을 기본으로 제공합니다.

취약점 동작 원리

CSRF가 낯설다면, 구체적인 예시를 통해 이해해 봅시다. 여러분의 애플리케이션에 인증된 사용자의 이메일 주소를 변경하는 POST /user/email 라우트가 있다고 가정합니다. 이 라우트는 폼 필드 email에 담긴 새 이메일 주소를 받아 처리합니다.

CSRF 보호가 없다면, 악의적인 외부 사이트가 다음과 같은 HTML 폼을 만들어 사용자 몰래 요청을 보낼 수 있습니다.

<form action="https://your-application.com/user/email" method="POST"> <input type="email" value="malicious-email@example.com"> </form> <script> document.forms[0].submit(); </script>

이 페이지를 방문하는 순간 폼이 자동으로 제출됩니다. 공격자는 여러분의 애플리케이션에 로그인된 사용자를 해당 페이지로 유인하기만 하면, 그 사용자의 이메일 주소가 공격자의 이메일로 바뀌게 됩니다.

이 취약점을 막으려면, 모든 POST, PUT, PATCH, DELETE 요청에 악의적인 외부 사이트가 접근할 수 없는 비밀 세션 값이 포함되어 있는지 검증해야 합니다.

CSRF 요청 방어

Laravel은 애플리케이션이 관리하는 각 사용자 세션마다 CSRF 토큰을 자동으로 생성합니다. 이 토큰은 실제로 인증된 사용자가 요청을 보냈는지 확인하는 데 사용됩니다. 토큰은 세션에 저장되며 세션이 재생성될 때마다 갱신되므로, 외부 사이트에서는 이 값에 접근할 수 없습니다.

현재 세션의 CSRF 토큰은 Request 객체의 세션이나 csrf_token() 헬퍼 함수로 가져올 수 있습니다.

use Illuminate\Http\Request; Route::get('/token', function (Request $request) { $token = $request->session()->token(); $token = csrf_token(); // ... });

POST, PUT, PATCH, DELETE 방식의 HTML 폼을 작성할 때는 반드시 숨겨진 _token 필드를 포함해야 합니다. CSRF 보호 미들웨어가 이 값을 검증합니다. Blade의 @csrf 디렉티브를 사용하면 간편하게 추가할 수 있습니다.

<form method="POST" action="/profile"> @csrf <!-- 아래 코드와 동일합니다 --> <input type="hidden" name="_token" value="{{ csrf_token() }}" /> </form>

web 미들웨어 그룹에 기본으로 포함된 App\Http\Middleware\VerifyCsrfToken 미들웨어가 요청에 담긴 토큰과 세션에 저장된 토큰이 일치하는지 자동으로 검증합니다. 두 값이 일치하면 요청이 실제 인증된 사용자로부터 온 것임을 확인할 수 있습니다.

CSRF 토큰과 SPA

Laravel을 API 백엔드로 사용하는 SPA를 개발하고 있다면, 인증 및 CSRF 보호 방법에 대해 Laravel Sanctum 문서를 참고하세요.

특정 URI를 CSRF 보호에서 제외하기

경우에 따라 일부 라우트를 CSRF 검증 대상에서 제외해야 할 수 있습니다. 예를 들어 결제 서비스(Stripe, 토스페이먼츠 등)의 웹훅을 수신하는 라우트가 있다면, 외부 서비스는 CSRF 토큰을 알 수 없으므로 해당 라우트를 제외해야 합니다.

이런 라우트는 routes/web.phpweb 미들웨어 그룹 밖에 정의하는 것이 일반적입니다. 또는 VerifyCsrfToken 미들웨어의 $except 속성에 URI를 추가하는 방법도 있습니다.

<?php namespace App\Http\Middleware; use Illuminate\Foundation\Http\Middleware\VerifyCsrfToken as Middleware; class VerifyCsrfToken extends Middleware { /** * CSRF 검증에서 제외할 URI 목록 * * @var array */ protected $except = [ 'stripe/*', 'http://example.com/foo/bar', 'http://example.com/foo/*', ]; }

NOTE

테스트 실행 중에는 편의를 위해 모든 라우트에서 CSRF 미들웨어가 자동으로 비활성화됩니다.

X-CSRF-TOKEN

VerifyCsrfToken 미들웨어는 POST 파라미터로 전달된 _token 외에도 X-CSRF-TOKEN 요청 헤더도 함께 확인합니다. 예를 들어, HTML의 <meta> 태그에 토큰을 저장해 두고:

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

jQuery 같은 라이브러리를 사용해 모든 AJAX 요청 헤더에 자동으로 토큰을 포함시킬 수 있습니다. 이 방법은 레거시 JavaScript 환경에서 AJAX 기반 애플리케이션을 보호할 때 유용합니다.

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

X-XSRF-TOKEN

Laravel은 현재 CSRF 토큰을 암호화된 XSRF-TOKEN 쿠키에 담아 매 응답과 함께 전송합니다. 이 쿠키 값을 읽어 X-XSRF-TOKEN 요청 헤더에 설정하면 CSRF 검증을 통과할 수 있습니다.

이 방식은 주로 개발 편의를 위해 제공됩니다. Angular, Axios 같은 JavaScript 프레임워크와 라이브러리는 동일 출처(same-origin) 요청 시 이 쿠키 값을 자동으로 X-XSRF-TOKEN 헤더에 포함시켜 줍니다.

NOTE

resources/js/bootstrap.js 파일에는 Axios HTTP 라이브러리가 기본으로 포함되어 있으며, Axios는 X-XSRF-TOKEN 헤더를 자동으로 전송합니다.

이 문서는 Laravel 공식 문서(MIT)를 한국 개발자를 위해 번역·재구성한 것입니다.

번역일: 2026년 6월 20일