얼마전에 본 기술면접에서
Preflight
에 대한 질문을 받았었는데 해당 질문에 대한 답변을 제대로 하지 못한 내 자신이 후회되어 작성하는Preflight
에 관한 포스팅이다..
Preflight
는 어떤 개념이고 어떤 역할을 하는지에 대해서 진득하게 알아보자.
브라우저가 본 요청을 보내기 전에 보내는 CORS 예비 요청
즉, 클라이언트에서 어떠한 요청을 보내기 전에 서버에다가 예비 요청을 보내서 해당 요청을 허용하는지 확인하는 요청인 것이다.
클라이언트가 브라우저를 통해 서버에 "이 요청을 보내도 괜찮습니까?"라고 물어보는 일종의 사전 확인 과정으로 생각해도 된다.
예를 들어, 우리가 사이즈가 큰 데이터를 서버에 보낸다고 가정해보자.
이를 위해, 프론트에서 해당 데이터를 위한 여러 처리를 하고 요청의 Body에 데이터를 담을 것이다.
하지만.. 해당 데이터를 보내는 요청을 서버에서는 허용하지 않는다면 프론트 단에서 해당 데이터를 위한 여러 처리는 결국 무효하게 되는 것이다.
또한 브라우저는 보안 상 민감한 요청을 처리하기 전, 해당 요청이 안전하고 허용되는지 서버에 확인해야 하는 경우 Preflight요청이 발생하게 된다.
Preflight
요청이 발생하기 위해서는 CORS(Cross-Origin Resource Sharing)정책에 따라 특정 요청이 Simple Request
의 기준을 벗어날 경우, Preflight
요청을 서버에 사전에 보내게 된다.
그럼 Simple Request
는 어떤 요청일까?
먼저 Simple Request
는 브라우저가 사전 확인 없이 보낼 수 있는 안전한 요청 유형을 의미한다.
GET, POST, HEAD 요청
요청 헤더는 User Agent에 의해 자동적으로 정해지는 헤더(Connection, User-Agent, fetch 스펙에 정의된 "forbidden header name")를 제외, fetch 스펙에 정의된 "CORS-safelisted request-header"포함하는 경우
Content-Type헤더에 application/x-www-form-urlencoded, text/plain, multipart/form-data정의
요청에 XMLHttpRequestUpload객체에 Event Listener 등록 x
요청에 ReadableStream객체가 사용 x
그럼, Preflight
Request는 어떤 상황에서 발생할까?
PUT, DELETE, CONNECT, OPTIONS, TRACE, PATCH 메서드를 사용하는 경우
금지된 헤더 이름, 커스텀 헤더를 사용하는 경우(Authorization, X-Custom-Header, X-Requested-With 등)
Content-Type헤더에 application/x-www-form-urlencoded, multipart/form-data가 아닌 경우
하나 이상의 Event Listener가 XMLHttpRequestUpload에 등록되어 있는 경우
즉 Preflight
가 발생하지 않는다면, Simple Requet
를 요청할 수 있다.
쉽게 생각하자면 클라이언트에서 보내려는 요청이 Preflight
요청에 의해서 요청을 받는 서버가 해당 요청이 유효한 요청인지 확인한 다음, 서버에서 유효한 요청으로 판단하면 원래 보내려고 했던 본 요청을 보내는 방식인 것이다.
OPTIONS
메서드는 클라이언트가 서버에 특정 리소스에 대해 사용할 수 있는 통신 옵션을 요청할 때 사용하는 메서드이다. 주로 서버와 클라이언트 간의 상호작용 가능성을 확인하거나, CORS정책에서 Preflight
요청을 수행할 때 사용된다.
해당 요청의 응답에는 클라이언트가 사용할 수 있는 메서드, 헤더, 인증 관련 정보를 응답하게 된다.
HTTP/1.1 200 OK
Allow: OPTIONS, GET, HEAD, POST
Cache-Control: max-age=604800
Date: Thu, 13 Oct 2016 11:45:00 GMT
Expires: Thu, 20 Oct 2016 11:45:00 GMT
Server: EOS (lax004/2813)
x-ec-custom-error: 1
Content-Length: 0
위와같이 서버가 허용한 메서드나 여러가지 옵션들을 확인할 수 있게 된다.
Preflight
요청은 원래부터 존재한 기능이 아니다.
옛날에는 웹 브라우저에서 서로 다른 도메인에 통신을 요청하는게 아닌 주로 같은 도메인에서 통신을 요청하는 형식이였다.
하지만, 웹 브라우저가 발전하면서 서로 다른 도메인에 통신을 하는 경우가 발생하며 생기게 된 요청이다.
다만 서로 다른 도메인에서 통신을 하는 경우 악의적인 웹사이트가 사용자의 정보를 탈취하거나 원치 않는 요청을 보낼 수 있다. 이를 막기 위해 CORS
개념이 생기게 된 것이다.
웹 개발을 하다보면 한번 쯤 CORS
에러와 마주친 경우가 있을 것이다.
CORS(Cross-Origin Resource Sharing)
는 브라우저 보안을 목적으로 2008년부터 표준화를 논의하기 시작하고, 2010년경부터 대부분의 브라우저에서 구현되었다. 이를 통해 웹 브라우저는 사용자 데이터의 안정성을 높일 수 있는 보안정책이다.
즉, CORS
는 서버가 명시적으로 다른 출처(Origin)의 요청을 허용할 수 있도록 설정하는 방식이다.
브라우저는 서버가 특정 조건을 만족할 때만 해당 요청을 허용하도록 정의할 수 있으며, 이를 통해 보안을 유지하면서도 필요한 경우 서로 다른 출처 간의 요청을 허용할 수 있게 해준다.
이번 포스팅에서는 Preflight
에 대해서 알아보았다.
프로젝트를 진행할 때 클라이언트에서 Preflight
요청을 보내는 것에 대해 간략한 개념만 보고 지나쳤는데 그런 나를 반성하는 포스팅이다..
앞으로의 개발을 대하는 나의 자세는 사소한 거여도 제발 가볍게 보지 말고 진득하게 한번 파보는 개발자가 되기를 미래의 나한테 바란다
https://developer.mozilla.org/ko/docs/Glossary/Preflight_request
https://velog.io/@serajang99/CORS-pre-flight%EC%98%88%EB%B9%84-%EC%9A%94%EC%B2%AD