CSRF 보호
업데이트됨번역일: 2026년 10월 8일
이 페이지는 원문이 업데이트되어 번역이 갱신되었습니다.
- 원문 수정
- 2026년 10월 7일
- 번역 갱신
- 2026년 10월 8일
CSRF 보호
소개
사이트 간 요청 위조는 인증된 사용자를 대신하여 허가받지 않은 명령을 수행하는 악의적인 공격입니다. Laravel은 애플리케이션을 사이트 간 요청 위조(CSRF)로부터 쉽게 보호할 수 있게 합니다.
취약점 동작 예시
CSRF가 어떻게 악용되는지 예를 들어 살펴보겠습니다. 인증된 사용자의 이메일 주소를 변경하는 POST 요청을 받는 /user/email 라우트가 있다고 가정합니다. 이 라우트는 보통 사용자가 새로 사용할 주소를 email 입력 필드로 전달받습니다.
CSRF 보호가 없다면 악성 사이트는 애플리케이션의 /user/email 라우트로 공격자 자신의 이메일 주소를 제출하는 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, QUERY 요청에 악성 애플리케이션이 접근할 수 없는 비밀 세션 값이 있는지 검사해야 합니다.
CSRF 요청 방지
기본적으로 web 미들웨어 그룹에 포함되는 Illuminate\Foundation\Http\Middleware\PreventRequestForgery 미들웨어는 두 단계 방식으로 CSRF를 방지합니다.
먼저 브라우저의 Sec-Fetch-Site 헤더를 확인합니다. 최신 브라우저는 모든 요청에 이 헤더를 자동으로 설정하여 동일 출처, 동일 사이트, 다른 사이트 중 어디에서 발생한 요청인지 나타냅니다. 동일 출처에서 온 요청이면 토큰 검증 없이 즉시 허용합니다.
헤더를 전송하지 않는 구형 브라우저이거나 보안 연결이 아닌 경우처럼 출처 검증을 통과하지 못하면 기존 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 지시어로 숨겨진 입력 필드를 쉽게 생성할 수 있습니다:
<form method="POST" action="/profile">
@csrf
<!-- Equivalent to... -->
<input type="hidden" name="_token" value="{{ csrf_token() }}" />
</form>CSRF 토큰과 SPA
Laravel을 API 백엔드로 사용하는 SPA를 만들고 있다면 API 인증 및 CSRF 방지 방법은 Laravel Sanctum 문서를 참고하세요.
출처 검증
앞서 설명한 것처럼 요청 위조 방지 미들웨어는 먼저 Sec-Fetch-Site를 확인하여 동일 출처 요청인지 판단합니다. 기본적으로 이 검사를 통과하지 못하면 CSRF 토큰 검증으로 전환합니다.
출처 검증만 사용하고 CSRF 토큰 검증으로의 전환을 완전히 비활성화하려면 bootstrap/app.php에서 preventRequestForgery를 사용합니다:
->withMiddleware(function (Middleware $middleware): void {
$middleware->preventRequestForgery(originOnly: true);
})출처 검증 전용 모드에서 검증에 실패한 요청은 일반적인 CSRF 토큰 불일치의 419 대신 403 HTTP 응답을 받습니다.
WARNING
브라우저는 보안 연결(HTTPS)에서만 Sec-Fetch-Site를 전송합니다. HTTPS로 서비스하지 않으면 출처 검증을 사용할 수 없으며 미들웨어는 CSRF 토큰 검증으로 전환합니다.
서브도메인 간 요청을 받아야 한다면(예: dashboard.example.com에서 example.com의 요청 수신) 동일 출처 외에 동일 사이트 요청도 허용할 수 있습니다:
->withMiddleware(function (Middleware $middleware): void {
$middleware->preventRequestForgery(allowSameSite: true);
})CSRF 보호에서 URI 제외
일부 URI를 CSRF 보호에서 제외해야 할 때가 있습니다. 예를 들어 Stripe로 결제를 처리하면서 웹훅을 사용한다면 Stripe는 라우트로 보낼 CSRF 토큰을 알지 못하므로 웹훅 처리 라우트를 제외해야 합니다.
일반적으로 이런 라우트는 Laravel이 routes/web.php의 모든 라우트에 적용하는 web 미들웨어 그룹 밖에 두는 것이 좋습니다. 또는 bootstrap/app.php의 preventRequestForgery에 URI를 전달하여 특정 라우트를 제외할 수 있습니다:
->withMiddleware(function (Middleware $middleware): void {
$middleware->preventRequestForgery(except: [
'stripe/*',
'http://example.com/foo/bar',
'http://example.com/foo/*',
]);
})NOTE
편의를 위해 테스트 실행 중에는 모든 라우트에서 CSRF 미들웨어가 자동으로 비활성화됩니다.
X-CSRF-TOKEN
PreventRequestForgery는 POST 매개변수의 CSRF 토큰 외에 X-CSRF-TOKEN 요청 헤더도 검사합니다. 예를 들어 HTML meta 태그에 토큰을 저장할 수 있습니다:
<meta name="csrf-token" content="{{ csrf_token() }}">그런 다음 jQuery 같은 라이브러리가 모든 요청 헤더에 토큰을 자동 추가하도록 설정합니다. 기존 JavaScript 기술로 만든 AJAX 애플리케이션에 간편하게 CSRF 보호를 적용할 수 있습니다:
$.ajaxSetup({
headers: {
'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
}
});X-XSRF-TOKEN
Laravel은 현재 CSRF 토큰을 암호화된 XSRF-TOKEN 쿠키에 저장하고 프레임워크가 생성하는 각 응답에 포함합니다. 이 쿠키 값으로 X-XSRF-TOKEN 요청 헤더를 설정할 수 있습니다.
이 쿠키는 주로 개발 편의를 위해 제공됩니다. Angular와 Axios 같은 일부 JavaScript 프레임워크 및 라이브러리는 동일 출처 요청에서 쿠키 값을 자동으로 X-XSRF-TOKEN 헤더에 넣습니다.