최근까지 Nginx를 앞단에 두고 로컬 환경에서 Docker로 개발하면서, 헤더(Header)를 적극적으로 활용하지 않았기 때문에 CORS의 프리플라이트 요청에 대해 깊이 알지 못했습니다. 특히 Spring에서는 프리플라이트 요청을 자동(설정을 해주면)으로 처리해주기 때문에, 이를 인지하지 못한 채 지나쳤던 것 같습니다. 이번에 Nginx 설정에서 Access-Token 헤더를 통해 요청을 보내면서, 다행스럽게(?) 프리플라이트 요청의 개념을 이해하게 되었습니다. 이를 계기로 프리플라이트 요청의 동작 방식과 어떤 상황에서 발생하는지를 정리하고자 이 글을 쓰게 되었습니다.
CORS는 웹 브라우저에서 교차 출처 요청(다른 도메인, 포트 또는 프로토콜로의 요청)을 제어하는 메커니즘입니다. 기본적으로 브라우저는 보안상 같은 출처(Same-Origin) 정책을 따르지만, CORS를 사용하면 특정 조건에서 다른 출처의 리소스에 접근할 수 있습니다.
프리플라이트 요청은 브라우저가 실제 요청 전에 서버에 미리 OPTIONS 요청을 보내어 해당 서버가 CORS 요청을 허용하는지 확인하는 과정입니다.
프리플라이트 요청은 클라이언트가 보내는 요청이 안전하지 않다고 간주되는 경우 발생합니다. 여기서 "안전하지 않음"은 서버에 잠재적인 영향을 미칠 수 있는 요청을 의미합니다. 브라우저는 이 요청이 허용될지 여부를 먼저 확인하기 위해 프리플라이트 요청을 전송합니다.
다음과 같은 조건에서 프리플라이트 요청이 발생합니다:
GET, POST, HEAD 외의 메서드일 때 (PUT, DELETE, PATCH 등).Authorization, Content-Type: application/json 등).application/json, multipart/form-data, text/xml 등).프리플라이트 요청은 OPTIONS 메서드를 사용해 전송됩니다.
프리플라이트 요청:
http
코드 복사
OPTIONS /api/resource HTTP/1.1
Host: example.com
Origin: http://my-website.com
Access-Control-Request-Method: PUT
Access-Control-Request-Headers: Content-Type
서버의 응답:
http
코드 복사
HTTP/1.1 204 No Content
Access-Control-Allow-Origin: http://my-website.com
Access-Control-Allow-Methods: PUT, GET, POST, DELETE
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Origin: 요청을 허용하는 출처.Access-Control-Allow-Methods: 허용된 HTTP 메서드.Access-Control-Allow-Headers: 허용된 요청 헤더.프리플라이트 요청은 성능에 영향을 미칠 수 있으므로 최대한 줄이는 것이 좋습니다. 이를 위해 다음을 고려할 수 있습니다:
GET, POST, HEAD로 제한.Content-Type을 application/x-www-form-urlencoded, multipart/form-data, text/plain 중 하나로 설정).Access-Control-Max-Age 헤더를 사용하여 프리플라이트 응답을 캐시할 수 있습니다. 이로 인해 브라우저가 일정 시간 동안 같은 출처로의 프리플라이트 요청을 다시 보내지 않게 됩니다.프리플라이트 요청은 브라우저가 교차 출처 HTTP 요청을 보내기 전에 보안을 확인하는 절차로, 서버가 허용하는 메서드와 헤더를 사전에 검증합니다. 이 과정은 보안 강화를 위해 필요하지만, 성능에 영향을 줄 수 있으므로 최대한 단순한 요청으로 구성하거나 캐싱을 활용하여 최소화하는 것이 중요합니다.