본문 바로가기
웹 개발

CORS(Cross-Origin Resource Sharing, 교차 출처 리소스 공유)

by xosoy 2024. 3. 26.

Origin(출처)

URL 구조에서 프로토콜, 호스트, 포트를 합친 것을 말한다.

예를 들어, https://example.com:8080/path/page?id=1의 경우

origin은 프로토콜(https), 도메인(example.com), 포트(8080)를 합친 https://example.com:8080이다.

 

cross-origin이란 origin이 서로 다른 경우, 즉 프로토콜, 도메인, 포트 번호 중 하나라도 다른 경우를 말한다.

  • http://example.com/app1https://example.com/app2  (다른 프로토콜)
  • http://example.comhttp://www.example.com (다른 도메인)
  • http://example.comhttp://example.com:8080 (다른 포트)

 

SOP(Same Origin Policy, 동일 출처 정책)

다른 Origin으로 요청을 보낼 수 없도록 하는 브라우저의 기본적인 보안 정책. 브라우저는 보낸 요청 및 서버로부터 받은 응답에 대해 동일한 출처인지 확인한다.

다만 예외적인 경우에는 다른 Origin으로 요청이 가능하다.

  • script 태그로 Javascript를 실행하는 경우
  • 이미지를 렌더링하는 경우
  • link 태그로 스타일시트를 불러오는 경우
  • HTML 문서를 화면에 보여주는 경우
  • CORS 정책을 사용하는 경우

 

SOP 정책을 통해 CSRF(Cross-Site Request Forgery)나 XSS(Cross-Site Scripting) 등의 공격을 방지할 수 있다. 

 

CORS(Cross-Origin Resource Sharing, 교차 출처 리소스 공유)

다른 Origin으로 요청을 보내기 위해 지켜야 하는 정책으로, SOP 정책을 피해 다른 Origin의 리소스를 허용시킬 수 있다.

 

동작 원리

CORS 요청은 요청 유형에 따라 다르게 동작한다.

 

단순 요청(Simple Request)

다음 조건을 모두 충족하는 요청은 안전한 요청으로 취급되어 Preflight(사전 전달)를 트리거하지 않는다.

단순 요청 조건

 

1. 클라이언트 HTTP 요청 - 헤더에 Origin 전달

Origin: http://localhost:3000

 

2. 서버 응답 - 헤더에 Access-Control-Allow-Origin 전달

Access-Control-Allow-Origin: http://localhost:3000

서버는 Access-Control-Allow-Origin접근이 허용되는 Origin을 기재하여 응답을 보낸다.

 

3. 클라이언트(브라우저)는 Origin과 서버가 보낸 Access-Control-Allow-Origin을 비교한다.

유효하지 않으면 응답을 버리고 CORS 에러를 발생시킨다.

유효하면 성공적으로 다른 Origin의 리소스를 가져오게 된다.

 

예비 요청(Preflight Request)

단순 요청 조건을 만족하지 않는 대부분의 경우 예비 요청을 보내 서버의 허가를 받은 후 실제 요청을 보낸다.

서버에 사이드 이펙트를 발생시키지 않는 OPTIONS 메소드를 사용하여, 실제 요청이 전송하기에 안전한지 확인한다.

 

1. 클라이언트의 프리플라이트 요청

  • OPTIONS 요청
  • Origin 헤더에 자신의 Origin 설정
  • Access-Control-Request-Method 헤더에 실체 요청에 사용할 메소드 설정
  • Access-Control-Request-Headers 헤더에 실체 요청에 사용할 헤더들 설정

 

2. 서버의 프리플라이트 요청에 대한 응답

  • Access-Control-Allow-Origin 헤더에 허용되는 Origin 설정
  • Access-Control-Allow-Methods 헤더에 허용되는 메소드 설정
  • Access-Control-Allow-Headers 헤더에 허용되는 헤더들 설정
  • Access-Control-Max-Age 헤더에 해당 프리플라이트 요청이 브라우저에 캐시될 시간(초) 설정

 

3. 클라이언트는 응답과 자신이 보낸 요청을 비교하여 안전한 요청인지 확인하고 실제 요청을 보낸다.

 

4. 실제 요청에 대해 서버가 응답한다.

 

 

인증 정보를 포함한 요청 (Credentialed Request)

클라이언트가 서버에게 자격 인증 정보(Credential; ex. 쿠키, 토큰)을 가지고 요청을 할 때를 말한다.

fetch 메소드의 경우 credentials 옵션에 인증 정보를 담을지를 명시할 수 있다. (axios는 withCredentials: true)

  • same-origin(default): 같은 출처 간 요청에만 인증 정보를 담는다
  • include: 모든 요청에 인증 정보를 담는다
  • omit: 모든 요청에 인증 정보를 담지 않는다

 

서버는 인증 정보를 포함한 요청에 대해서는 다른 대응이 필요하다.

  • 응답 헤더의 Access-Control-Allow-Credentials를 true로 설정
  • 응답 헤더의 Access-Control-Allow-Origin에 와일드카드(*)가 아닌 분명한 Origin 설정

브라우저(클라이언트)는 Access-Control-Allow-Credentials: true 헤더가 없는 응답은 거부한다.

 

 

 

 

참고

https://etloveguitar.tistory.com/83

https://it-eldorado.tistory.com/163

https://developer.mozilla.org/ko/docs/Web/HTTP/CORS#%EB%8B%A8%EC%88%9C_%EC%9A%94%EC%B2%ADsimple_requests