CORS 정리

__〆( ̄ー ̄ ) ·2022년 7월 22일
0

들어가며

웹 서비스 개발 시 한번 쯤은 마주치게 되는 CORS error에 대해 명확하게 이해하고 정리해보자. 교차 출처 리소스 공유(CORS, Cross Origin Resource Sharining)에 대해 이해하려면 먼저 동일 출처 정책(SOP, Same Origin Policy)를 알아야한다.


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

동일 출처 정책에 대한 정의를 찾아보면 다음과 같다.

동일 출처 정책 - 웹 보안 | MDN
동일 출처 정책(same-origin policy)은 어떤 출처에서 불러온 문서나 스크립트가 다른 출처에서 가져온 리소스와 상호작용하는 것을 제한하는 중요한 보안 방식입니다. 동일 출처 정책은 잠재적으로 해로울 수 있는 문서를 분리함으로써 공격받을 수 있는 경로를 줄여줍니다.

동일 출처 정책을 통해 우리가 방어할 수 있는 대표적인 웹 취약점 공격으로는 크로스 사이트 스크립팅(Cross Site Scripting, XSS)사이트간 요청 위조(Cross Site Request Forgery, CSRF)가 있다.

여기서 핵심 키워드는 Cross Site이다. 즉 다른 출처(Cross Site)의 리소스를 무분별하게 허용할 경우 우리의 웹 애플리케이션은 위와 같은 공격들에 취약해진다. 동일 출처 정책은 이와 같은 공격을 방어하기 위한 보안 방식으로 후에 설명할 CORS error 또한 동일 출처 정책관련이 있다.

출처 (Origin)의 정의

출처를 간단하게 말로 표현하면 리소스를 가져온 장소이다. 웹에서는 출처를 다음과 같이 정의 한다.

출처 = 프로토콜 + 호스트 + 포트
예시 = 프로토콜(https://) + 호스트 (velog.io) + 포트(443, 기본 포트인 경우 생략)

따라서 동일 출처는 위 3가지가 같은 경우를 의미하고 리소스의 경로는 상관 없다.
아래 표는 URL https://velog.io/@usimebul/CORS와 출처를 비교한 예시이다.

URL결과이유
https://velog.io/@usimebul/포스팅1성공경로만 다름
https://velog.io/@usimebul/group1/포스팅1성공경로만 다름
http://velog.io/@usimebul/CORS실패프로토콜 다름
https://velog.io:8443/@usimebul/CORS실패포트 다름 (http://는 80이 기본값)
https://velogger.io/@usimebul/CORS실패호스트 다름

Internet Explorer의 경우 예외 사항이 존재하는데 해당 포스트에서는 다루지 않음으로 관심이 있는 경우 동일 출처 정책 - 웹 보안 | MDN을 참조하자.


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

동일 출처 정책이 중요 보안 모델이긴 하지만 웹 애플리케이션을 개발하다보면 다른 출처의 리소스를 사용하게 되는 경우가 있다. 이 경우 CORS를 통해 다른 출처의 리소스를 사용할 수 있다. CORS에 대한 정의를 찾아보면 다음과 같다.

교차 출처 리소스 공유 (CORS) - HTTP | MDN
교차 출처 리소스 공유(Cross-Origin Resource Sharing, CORS)는 추가 HTTP 헤더를 사용하여, 한 출처에서 실행 중인 웹 애플리케이션이 다른 출처의 선택한 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제입니다. 웹 애플리케이션은 리소스가 자신의 출처(도메인, 프로토콜, 포트)와 다를 때 교차 출처 HTTP 요청을 실행합니다.

즉 우리가 맞이하는 CORS error는 웹 브라우저에게 다른 출처의 리소스를 접근할 수 있는 권한이 없을 경우 발생하는 오류이다.

기능적 개요

웹 브라우저는 CORS 요청에 대해 OPTIONS 메서드로 프리플라이트(Preflight, 사 전달) 요청을 보내 HTTP 응답 헤더에 정의된 리소스 접근 권한을 확인하고 권한이 충족되는 경우에 해당 요청을 보낸다.

프리플라이트를 호출하지 않는 단순 요청의 경우도 HTTP 응답 헤더에 리소스 접근 권한이 없는 경우 웹 브라우저는 CORS error를 발생시킨다. 즉 클라이언트의 CORS 요청을 허용하고자 하는 경우 서버에서 응답 헤더들을 통해 권한을 부여해주어야 한다.

HTTP 응답헤더

CORS를 정의하는 HTTP 응답 헤더는 다음과 같다.

  • Access-Control-Allow-Origin: <origin> / *
    특정 출처(origin) 또는 모든 출처(*)에 대해 리소스 요청 허용
    모든 출처를 허용하는경우 인증 정보를 포함할 수 없음
  • Access-Control-Expose-Headers: <header-name> [, <header-name>]*
    브라우저가 접근할 수 있는 헤더를 서버의 화이트리스트에 추가
  • Access-Control-Max-Age: <delta-seconds>
    프리플라이트 요청 결과를 캐시할 수 있는 시간
  • Access-Control-Allow-Methods: <method> [, <method>]*
    리소스 요청 시 허용되는 메서드 목록
  • Access-Control-Allow-Headers: <header-name> [, <header-name>]*
    표준 HTTP 헤더 외에 리소스 요청 시 허용되는 헤더 목록
  • Access-Control-Allow-Credentials: true
    인증 정보(credentials)를 포함하는 요청 허용 여부

일반적으로 Access-Control-Allow-OriginAccess-Control-Allow-Methods 응답 헤더 설정을 통해 대부분의 CORS error가 해결된다. 여기서 가장 흥미로운 부분은 인증 정보를 포함하는 요청에 대한 언급이다.

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

인증 정보(credentials)에 해당하는 정보는 HTTP cookiesHTTP Authentication이 있다. 이 정보는 서버의 입장에서 보면 사용자 인증과 로그인 세션 유지 등으로 사용되는 정보들이다.

앞서 언급한 CSRF 공격이 바로 인증 정보를 포함한 요청을 통해 사용자가 원하지 않은 행동 (게시글 작성, 계좌 이체 등)을 하도록 하는 것이다. 따라서 인증 정보를 포함하는 요청의 경우 신중해야하기 때문에 Access-Control-Allow-OriginAccess-Control-Allow-Credentials를 통해 추가적인 권한을 부여해주어야 한다. 일반적으로 CORS 요청 시 인증 정보를 포함시켜야 하는 경우 서비스 구조의 변경을 고려해야한다.

CORS 오류 해결

profile
뭐라도 적자

0개의 댓글