Blog

CORS와 사전 요청: 브라우저가 다른 출처를 읽는 조건

“Eureka Client끼리 통신할 때도 CORS를 설정해야 하는가?”가 헷갈려 개념을 다시 정리했습니다. CORS는 브라우저가 다른 출처에 접근할 때 따르는 규칙입니다.

같은 출처의 기준

SOP(Same-Origin Policy)는 동일 출처 정책입니다. 출처는 호스트만이 아니라 프로토콜, 호스트, 포트의 조합으로 구분합니다.

  • cat.com과 dog.com은 호스트가 다릅니다.
  • cat.com과 big.cat.com은 서브도메인이 달라 다른 출처입니다.
  • 기본 포트의 cat.com과 cat.com:8080은 포트가 다릅니다.
  • http://cat.com과 https://cat.com은 프로토콜이 다릅니다.

예를 들어 https://www.naver.com의 페이지에서 https://api.cat.com으로 요청하면 교차 출처 요청입니다. 응답을 브라우저의 스크립트에서 읽으려면 서버의 CORS 허용 조건을 만족해야 합니다.

CORS(Cross-Origin Resource Sharing)는 SOP가 제한하는 교차 출처 응답 읽기를 필요한 범위에서 허용합니다. 서버가 HTTP 헤더로 허용할 출처 등을 알려 주면 브라우저가 이를 적용하는 방식입니다.

당시에는 SOP를 XSS와 CSRF를 막기 위해 생긴 정책으로 단순하게 이해했습니다. 하지만 CORS는 두 공격을 대신 막는 장치가 아닙니다. 특히 단순 교차 출처 요청은 서버까지 도달할 수 있으므로 응답 읽기 제한만으로는 CSRF를 방어할 수 없습니다.

사전 요청 없이 보내는 요청

흔히 Simple Request라고 부르는 요청은 사전 요청 없이 전송됩니다. 대표 조건은 세 가지입니다.

  • 메서드가 GET, HEAD, POST 중 하나입니다.
  • 직접 추가하는 헤더가 Accept, Accept-Language, Content-Language, Content-Type, Range 등 CORS 안전 목록의 조건을 만족합니다.
  • Content-Type은 text/plain, multipart/form-data, application/x-www-form-urlencoded 중 하나입니다.

헤더는 이름과 함께 값에도 제한이 있으며 Range는 단일 범위여야 합니다. 요청 방식에 따른 추가 조건도 있습니다. 사전 요청을 생략해도 응답을 읽을 때 CORS 검사는 적용됩니다.

OPTIONS로 먼저 확인하는 요청

안전 목록의 조건을 벗어나는 요청은 일반적으로 실제 요청에 앞서 preflight, 즉 사전 요청을 보냅니다. 브라우저가 OPTIONS 메서드로 대상 서버에 출처, 사용할 메서드와 헤더의 허용 여부를 확인하고 허용되면 실제 요청을 보냅니다.

이때 요청 메서드를 알리는 헤더 이름은 단수형 Access-Control-Request-Method입니다. Origin은 POST 여부와 관계없이 브라우저가 교차 출처 요청을 처리하며 관리하는 헤더입니다.

브라우저가 OPTIONS 사전 요청 후 실제 요청을 보내는 순서

인증 정보를 포함하는 요청

쿠키 등 인증 정보를 포함하는 요청은 Credentialed Request라고 부릅니다. 이는 단순 요청과 사전 요청에 나란히 놓인 제3의 분류가 아니라 별도의 조건입니다. 인증 정보를 포함하면서도 사전 요청이 없는 경우가 있습니다.

교차 출처 응답을 인증 정보와 함께 허용하려면 Access-Control-Allow-Credentials: true와 구체적인 허용 출처가 필요하고 Access-Control-Allow-Origin: *는 사용할 수 없습니다. Authorization처럼 직접 추가한 헤더도 사전 요청 조건을 별도로 봐야 합니다.

확인할 헤더

  • Access-Control-Allow-Origin: 응답을 읽도록 허용할 출처
  • Access-Control-Request-Method: 사전 요청에서 알리는 실제 요청 메서드
  • Access-Control-Request-Headers: 사전 요청에서 알리는 실제 요청 헤더
  • Access-Control-Allow-Methods: 서버가 허용하는 메서드
  • Access-Control-Allow-Headers: 서버가 허용하는 요청 헤더
  • Access-Control-Max-Age: 사전 요청 결과를 캐시할 수 있는 시간
  • Access-Control-Allow-Credentials: 인증 정보를 포함한 응답 허용 여부
  • Access-Control-Expose-Headers: 스크립트가 추가로 읽을 수 있는 응답 헤더

와일드카드는 용도에 따라 쓸 수 있지만 비공개 데이터를 다루는 서비스에서는 허용할 출처를 명확히 정하는 편이 좋습니다.

서버끼리 통신한다면

일반적인 서버 간 HTTP 클라이언트는 브라우저의 SOP와 CORS 검사를 적용하지 않습니다. 그래서 서버끼리 통신한다는 이유만으로 CORS를 설정할 필요는 없지만 인증과 권한 검사는 여전히 필요합니다.

참고 자료