서버 액세스 로그를 분석하던 도중 처음보는 메소드의 요청을 하나 발견합니다.
OPTIONS? 뭔가하고 확인해봤더니 Request Body도 Response Body도 없습니다. 무엇을 위한 요청일까요?
이를 알아보기 전에 SOP라는 웹 브라우저 정책에 대해 살펴보고 넘어가야합니다.
SOP : Same Origin Policy (동일 출처 정책)
- MDN 문서에 따른 SOP의 정의는 다음과 같습니다.
- SOP란 한 origin에서 불러온 문서 / 스크립트가 다른 origin과 상호작용하는 것을 제한하는 웹 브라우저 정책입니다.
- 다시 말하면, 같은 origin 으로만 요청을 주고 받을 수 있다는 뜻입니다.
- 조금 더 정확히 말하면, 다른 origin 으로의 read를 불허합니다.
- 그래서 자바 스크립트는 자신이 실행된 문서의 서버와 다른 서버에서 불러온 문서의 내용은 읽을 수 없습니다.
- 다만, 다른 origin 으로의 링크, 리다이렉트, form submit 등의 write 작업은 허용합니다.
origin(출처)의 정의
- 어떤 두 URL의 protocol(scheme), host(domain name), port가 일치할 경우 둘은 같은 origin 입니다.
- http://store.company.com/dir/page.html 을 기준으로 같은 origin 인지 아닌지 비교한 표입니다.
SOP의 의미?
- SOP가 다른 origin에 대한 자원 혹은 그에 대한 접근을 제한하는 정책이라는 것은 알겠는데,
- 왜 그런 정책이 만들어 졌을까요?
- SOP 를 무시하고 다른 origin 의 문서와 마구잡이로 상호작용이 가능하다면 보안상 큰 문제가 발생할 수 있습니다.
- 여기서 말하는 보안상의 문제란?
- 제가 aaa.com 이라는 웹 사이트를 만들었다고 가정하겠습니다. 나름 실사용 유저도 많이 보유하고 성공한 웹사이트입니다.
- 하지만 나쁜 의도를 가진 사람이 xyz.com 이라는 자신의 웹 서버로 유저를 유도하는 스크립트를 작성했습니다.
- 이 스크립트가 제 웹사이트에서 작동 가능해버리면 유저의 개인 정보는 xyz.com 으로 다 넘어가 버리겠죠.
- 그래서 SOP 를 통해 다른 origin의 문서는 읽지 못하도록 막습니다.
CORS : Cross-Origin Resource Sharing (교차 출처 리소스 공유)
- 하지만 SOP 에 따르면 aaa.com 이라는 웹 사이트는 bbb.com 이라는 제가 만든 api 서버와도 통신할 수 없습니다. origin 이 다르기 때문이죠.
- 그래서 SOP 를 우회하기 위한 여러가지 방법 중 가장 안전하고 또 권장되는 방법이 CORS 입니다.
- MDN 문서에 따른 CORS의 정의는 다음과 같습니다.
- CORS란 HTTP header에 추가적인 정보를 추가하여 서버가 브라우저에게 자기 자신뿐만 아니라 다른 origin 에서 요청한 정보도 허용할 수 있도록 알려주는 것을 말합니다.
- 만약 aaa.com 이라는 웹사이트가 bbb.com 이라는 api 서버의 자원을 사용하고 싶다면,
- bbb.com 에 먼저 자신(aaa.com)이 요청을 보내도 되는지 물어봐야합니다.
- 이 과정을 pre-flight 라 부릅니다.
- aaa.com 에서 bbb.com 에 요청을 보낼 때 htttp header에
{ Origin : aaa.com }
으로 요청하는 출처를 반드시 명시해 주고 - 서버가 다시 응답을 보낼 때 http header 에
{ Access-Control-Allow-Origin : 허용하는 주소 }
로 CORS 를 허용할 URI 을 명시해 줍니다. - 그러면 브라우저는 해당 http header를 해석하여 요청을 승인할지 거부할지 판단합니다.
- 브라우저가 승인하면 비로소 본래 하려던 요청을 서버에 보냅니다.
- 위 pre-flight 절차에서 서버에게 요청할 때 사용하는 HTTP 메소드가 우리가 궁금했던 OPTIONS 메소드입니다.
OPTIONS
- OPTIONS 메소드를 사용한 pre-flight 요청의 예시입니다.
- 클라이언트는 먼저 서버로 OPTIONS 요청에 Origin 헤더를 담아 보내고,
- 서버는 그에 대한 응답으로
Access-Control-Allow-Origin
헤더에 CORS 를 허용하는 URI 목록을 담아 보냅니다. (CORS 에 관여하는 부가적인 다른 헤더들도 존재합니다. e.g.Access-Control-Allow-Methods
,Access-Control-Allow-Headers.
..) - 해당 응답을 브라우저가 해석하여 CORS가 허용되었다 판단하면, 본래 보내려면 POST 요청을 서버로 보냅니다.
- OPTIONS는 서버에서 추가 정보를 판별하는데 사용하는 HTTP/1.1 메서드이며,
- safe 메서드이기 때문에 리소스를 변경하는데 사용할 수 없습니다.
하지만 모든 요청마다 OPTIONS 요청을 하는 것은 아닙니다.
- 아래의 3가지 조건을 모두 만족하는 요청은 pre-flight 과정을 생략합니다.
GET
,HEAD
,POST
메소드 중 하나- user agent에 의해 자동으로 설정되는 (Connection, User-Agent, Fetch 스펙상 forbidden header로 정의되어 있는) 헤더외에 CORS-safelisted request-header로 명시된 헤더들만 포함된 경우 (
Accept
,Accept-Language
,Content-Language
,Content-Type
등) - Content-Type은
application/x-www-form-urlencoded
,multipart/form-data
,text/plain
중 하나
- 위 3가지 조건 중 하나라도 만족하지 않는 요청은 pre-flight 요청을 먼저 보냅니다.