본문 바로가기

CSRF 보호

번역일: 2026년 6월 20일

CSRF 보호

소개

CSRF(Cross-Site Request Forgery, 사이트 간 요청 위조)는 인증된 사용자의 권한을 악용해 그 사람도 모르는 사이에 악의적인 요청을 보내는 공격입니다. Laravel은 이러한 CSRF 공격으로부터 애플리케이션을 쉽게 보호할 수 있는 기능을 기본으로 제공합니다.

취약점 예시

CSRF가 어떻게 악용되는지 구체적인 예를 들어 설명하겠습니다. 여러분의 애플리케이션에 /user/email 라우트가 있고, 이 라우트는 POST 요청을 받아 인증된 사용자의 이메일 주소를 변경한다고 가정합니다.

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 토큰은 요청 객체의 세션이나 csrf_token 헬퍼 함수로 가져올 수 있습니다.

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

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

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

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

CSRF 토큰과 SPA

Laravel을 API 백엔드로 사용하는 SPA를 개발 중이라면, API 인증 및 CSRF 보호에 관한 자세한 내용은 Laravel Sanctum 문서를 참고하세요.

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

특정 URI는 CSRF 보호에서 제외해야 할 때가 있습니다. 예를 들어, PG사(결제 대행사)의 웹훅을 처리하는 라우트가 여기에 해당합니다. 외부 서비스에서 직접 호출하는 웹훅은 CSRF 토큰을 포함할 방법이 없기 때문입니다.

이런 라우트는 routes/web.phpweb 미들웨어 그룹 밖에 정의하는 것이 일반적입니다. 또는 bootstrap/app.php 파일에서 validateCsrfTokens 메서드를 통해 특정 URI를 명시적으로 제외할 수도 있습니다.

->withMiddleware(function (Middleware $middleware): void { $middleware->validateCsrfTokens(except: [ 'stripe/*', 'http://example.com/foo/bar', 'http://example.com/foo/*', ]); })

NOTE

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

X-CSRF-TOKEN

ValidateCsrfToken 미들웨어는 POST 파라미터의 _token 값뿐만 아니라, X-CSRF-TOKEN 요청 헤더도 함께 확인합니다. 예를 들어, 아래와 같이 HTML <meta> 태그에 토큰을 저장해 두면 AJAX 요청에 활용하기 편리합니다.

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

그런 다음 jQuery와 같은 라이브러리를 설정해 모든 AJAX 요청 헤더에 토큰을 자동으로 포함시킬 수 있습니다.

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

이 방식은 레거시 JavaScript 환경의 AJAX 기반 애플리케이션에서도 간단하고 편리하게 CSRF 보호를 적용할 수 있습니다.

X-XSRF-TOKEN

Laravel은 프레임워크가 응답을 생성할 때마다 현재 CSRF 토큰을 암호화된 XSRF-TOKEN 쿠키에 담아 전송합니다. 이 쿠키 값을 꺼내 X-XSRF-TOKEN 요청 헤더에 설정할 수 있습니다.

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

NOTE

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

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

번역일: 2026년 6월 20일