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 필드를 포함해야 합니다. 가장 간편한 방법은 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를 개발하는 경우에는 Laravel Sanctum 문서를 참고하세요. Sanctum은 API 인증과 CSRF 방어를 SPA 환경에 맞게 처리하는 방법을 안내합니다.
특정 URI를 CSRF 보호에서 제외하기
일부 URI는 CSRF 보호에서 제외해야 할 때가 있습니다. 대표적인 예로, 외부 결제 서비스(예: Stripe, 아임포트 등)의 웹훅(Webhook) 라우트가 있습니다. 외부 서비스는 여러분 애플리케이션의 CSRF 토큰을 알 수 없으므로, 해당 라우트에서는 CSRF 검증을 비활성화해야 합니다.
이러한 라우트는 가능하면 routes/web.php의 web 미들웨어 그룹 바깥에 정의하는 것이 좋습니다. 특정 URI만 선택적으로 제외하려면 bootstrap/app.php 파일에서 validateCsrfTokens 메서드를 사용하세요.
->withMiddleware(function (Middleware $middleware) {
$middleware->validateCsrfTokens(except: [
'stripe/*',
'http://example.com/foo/bar',
'http://example.com/foo/*',
]);
})NOTE
테스트 실행 중에는 CSRF 미들웨어가 모든 라우트에서 자동으로 비활성화됩니다.
X-CSRF-TOKEN
ValidateCsrfToken 미들웨어는 POST 파라미터의 _token 값뿐만 아니라, X-CSRF-TOKEN 요청 헤더도 함께 검사합니다. 이를 활용하면 AJAX 기반 애플리케이션에서도 CSRF 토큰을 편리하게 전달할 수 있습니다.
일반적인 방법은 HTML의 <meta> 태그에 토큰을 저장하는 것입니다.
<meta name="csrf-token" content="{{ csrf_token() }}">이후 jQuery 같은 라이브러리를 사용해 모든 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) 요청 시 XSRF-TOKEN 쿠키를 자동으로 읽어 X-XSRF-TOKEN 헤더에 설정해 주기 때문에 개발 편의성이 높습니다.
NOTE
resources/js/bootstrap.js 파일에는 Axios HTTP 라이브러리가 기본으로 포함되어 있으며, Axios는 X-XSRF-TOKEN 헤더를 자동으로 전송합니다. 별도의 설정 없이도 CSRF 보호가 동작합니다.