티스토리 뷰

CORS


"저희는 이 api 클라이언트에서 써야하는데.. 그럼 CORS 처리해주시나요?"

 

최근 회사에서 통합 검색 api를 다른 도메인으로 요청하라는 개발 사항을 전달 받고 다시 떠오른 CORS 이슈.

누구나 겪었지만, 누구나 제대로 알고 처리하는 것은 아니기에 이제라도 제대로 정리해보자는 마음으로 정리해본다. 

 

CORS를 설명하기 위해서는 먼저  SOP를 알아야 한다.

 

SOP

📮 Same-origin Policy (동일 출처 정책) 란?

Same-origin Policy(MDN)

: 하나의 출처에서 만들어진 문서/스크립트가 다른 출처의 자원과 어떻게 상호작용 할 것인가에 대해 제한하는 주요 보안 방식
: The same-origin policy is a critical security mechanism that restricts how a document or script loaded by one origin can interact with a resource from another origin.  

 

SOP란 말 그대로 보안을 위해 동일 출처의 요청에만 응답하도록 만든 정책이다. 예컨데, 악의적인 웹 사이트의 공격으로 개인적인 정보 (메일이나 회사 인트라넷 정보 등)가 유출 되는 문제를 해결하기 위해 브라우저에서 지원한다.

💡 Same-origin(동일 출처) 란?

그렇다면 동일 출처란 무엇일까? 쉽게 설명하자면 Protocol, Port, Hostname 같은 URL을 의미한다.

URL 구성 요소

 

그렇다면 다음중 http://localhost와 동일 출처인 url을 찾아보자.

URL 동일 출처 여부
https://localhost X
http://localhost:80 O
http://127.0.0.1 X
http://localhost/api/cors O

정답은 2, 4번이다. http의 경우 기본 포트가 80포트가 생략되어 있기 때문에 2번과 같다. 4번의 경우 protocol, port, host가 같고 path만 다르다. 

Cross-origin 지원

만약 다른 서버로 부터 응답을 받고 싶다면 어떻게 해야할까? 브라우저에서는 이미 몇가지 방식의 http요청에서 cross-origin을 허용하고 있다. (embedded CORS) 그 사례는 아래와 같다.

  • <script src="…"></script>
  • <link rel="stylesheet" href="…">
  • <img>
  • <video>
  • <iframe>
  • @font-face

그 밖의 교차 출처를 허용하기 위해서는 서버가 HTTP 응답 헤더에 허용하는 다른 출처를 명시해야 한다.

 

CORS

CORS

 

📮 Cross-Origin Resource Sharing (교차 출처 리소스 공유) 란?

CORS

추가 HTTP헤더를 사용하여, 한 출처에서 실행중인 웹 어플리케이션이 다른 출처의 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제


그렇다. CORS를 오류가 아니고, 일종의 정책이다.  아래 세가지 요청 방식에 따라 '교차 출처 간 정보 공유'(cross-origin resource sharing)를 할 수 있다.

Preflight Request

  • OPTIONS 메서드를 통해 다른 도메인의 리소스로 HTTP요청을 보내 실제 요청이 전송하기에 안전한지 확인하는 방법
  • cross-origin 요청으로 인해 실제 서버 데이터에 영향을 주지 않기 위해 사용된다.

요청 헤더 및 응답 헤더에 필요한 정보들

Simple Request

  • preflight와 달리 cross-origin을 별도 확인과정 없이 바로 자원을 요청하는 방법
  • Simple Request의 문제점 - 서버가 CORS처리가 되어 있지 않을 경우를 고려하지 않는다. (멱등하지 않은 HTTP 요청시 문제)
  • Content-Type 헤더는 다음의 값들만 허용된다.
    • application/x-www-form-urlencoded
    • multipart/form-data
    • text/plain

Credential Request

  • HTTP 헤더에 인증 정보를 포함하여 요청하는 방법
  • Access-Control-Allow-Origin에 *를 포함할 수 없음.
  • 아래는 토스 테크 블로그에서 Credential 요청으로 toss.tech에서 api-public.tosss.im으로 블로그 정보를 가지고 온 경우

 

CORS 오류 대응하기

Access to XMLHttpRequest at {server url} from origin {client url} has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.

 

cors를 제대로 이해했다면, CORS오류에 대응하기 쉬워진다. 위에 세가지 방법 중 하나의 방법을 선택하고, api 요청 헤더 및 응답 헤더에 필요 정보를 기록하면 된다. 일반적으로 응답헤더에 Acccess-Conrol-Allow-Origin에 *를 넣고 처리하기 쉽지만, 이건 보안상 위험하기 때문에 좋은 방법이 아니다. 특별히 멱등하지 않은 HTTP 메소드(POST, PATCH)를 사용할 때는 preflight 또는 credential을 필수적으로 고려해야 한다. 

Cf. 프록시 서버 설정으로 Same-origin인 척하기

일반적으로 프레임워크에서 프록시 설정하는 것도 CORS 때문이다.  배포전 로컬환경에서 개발할 때에는 위와같은 CORS오류를 해결하기 위해 NextJs, NuxtJs 등의 프록시 설정을 사용한다. 

프록시 서버란?

: 클라이언트가 다른 네트워크에 접속할 수 있도록 중간에서 대리해주는 서버를 의미한다. 

 

아래는 Nuxt에서 Nitro를 사용하여 프록시 설정을 한 예시이다.

export default defineNuxtConfig({
  // 생략
  nitro: {
    compressPublicAssets: true,
    devProxy: {
      "/es/": {
        target: process.env.APP_API_URL + "/es",
        changeOrigin: true,
      },
      "/es/**": {
        target: process.env.APP_API_URL + "/es/**",
        changeOrigin: true,
      },
    },
  },

 

Reference

내 지식으로 만들기 위해 포스팅을 하지만, 사실상 공부하다 보면 이미 잘 정리되어 있는 곳이 너무나도 많은거 같다.

 

교차 출처 리소스 공유 (CORS) - HTTP | MDN

교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)는 추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라

developer.mozilla.org

 

 

🌐 악명 높은 CORS 개념 & 해결법 - 정리 끝판왕 👏

악명 높은 CORS 에러 메세지 웹 개발을 하다보면 반드시 마주치는 멍멍 같은 에러가 바로 CORS 이다. 웹 개발의 신입 신고식이라고 할 정도로, CORS는 누구나 한 번 정도는 겪게 된다고 해도 과언이

inpa.tistory.com