CORS, SOP란 무엇일까? CORS 에러 회피하기!
CORS (Cross-Origin Resource Sharing)란 무엇인가?
CORS에 대해 알아보려면, 먼저 SOP에 대해 알고 있어야 이해가 잘 된다.
SOP(Same-Origin Policy)란?
SOP는 브라우저에서 관리하는 웹 보안을 위한 정책으로, 동일 출처(같은 프로토콜, 도메인, 포트)를 갖는 리소스 간에만 자유로운 상호작용을 허용한다. 이를 통해 잠재적인 보안 위협을 방지한다. SOP는 클라이언트 측(JavaScript)이 다른 출처의 리소스를 직접적으로 접근하지 못하게 한다.
Origin 판단 기준
출처(Origin)는 프로토콜, 도메인, 포트 세 가지 요소로 정의된다. 세 요소가 모두 동일할 때, 두 리소스는 동일 출처로 간주된다.
- 프로토콜:
http://
와https://
는 다른 출처로 간주된다. - 도메인(호스트):
www.example.com
과api.example.com
은 다른 출처로 간주된다. - 포트:
https://www.example.com:443
과https://www.example.com:8443
은 다른 출처로 간주된다.
브라우저에서 SOP가 적용되는 항목
SOP는 JavaScript와 관련된 특정 리소스에 대해 엄격히 적용된다.
- JavaScript AJAX 요청: 다른 출처로의 XMLHttpRequest 및 Fetch API 요청은 SOP에 의해 차단된다.
- Window 객체 접근: 다른 도메인의 웹 페이지에서
window
객체를 통한 DOM 접근은 SOP에 의해 차단된다.
SOP가 적용되지 않는 항목
SOP는 일부 HTML 태그를 통한 리소스 로딩에는 적용되지 않는다. 이러한 태그는 안전하게 다른 출처에서 리소스를 가져올 수 있도록 설계되어 있다.
<img>
태그: 다른 출처의 이미지를 불러오는 것은 허용된다.<script>
태그: 다른 출처의 스크립트를 로드하는 것은 허용된다. 그러나 스크립트 실행은 별도의 보안 메커니즘에 의해 관리된다.<link>
태그: 다른 출처의 스타일시트(CSS)를 로드하는 것은 허용된다.<iframe>
태그: 다른 출처의 페이지를 포함하는 것은 허용되지만, 상호작용은 제한적이다.
CORS(Cross-Origin Resource Sharing)
CORS는 SOP의 제약을 해결하기 위해 사용된다. 즉, SOP를 회피하여 다른 출처의 리소스와 상호 작용할 수 있도록 설정할 수 있다. 서버는 CORS 헤더를 통해 특정 출처의 요청을 허용한다.
- 동작 원리:
- 서버는 응답 헤더에
Access-Control-Allow-Origin
을 포함하여 요청을 허용할 출처를 명시한다. - 브라우저는 요청의
Origin
과 서버의Access-Control-Allow-Origin
헤더를 비교하여 요청을 허용할지 결정한다.
- 서버는 응답 헤더에
1. 사용자(브라우저) - 'www.example.com' 접속
2. 'www.example.com'에서 ajax 통신으로 'www.api.example.com'으로 리소스 요청
3. 이때, 요청 헤더에는 Origin: www.example.com 이 담긴다.
4. 'www.api.example.com'은 리소스를 응답
5. 이때, 응답 헤더에는 Access-Control-Allow-Origin: www.example.com 이 담긴다.
6. 브라우저는 요청 Origin과 응답 Access-Control-Allow-Origin 비교
7. 두 출처가 동일함을 확인하고 리소스 허용
CORS Preflight request란?
브라우저가 실제 요청을 보내기 전에 서버가 요청을 허용하는지 확인하기 위해 보내는 초기 OPTIONS 요청이다. 이는 특히 복잡한(complex) 교차 출처 요청에서 사용된다. 즉, CORS 동작을 하기 이전에 한 번의 요청이 더 추가된다.
복잡한(Complex) 교차 출처 요청
다음 중 하나를 포함하는 요청은 복잡한 요청으로 간주된다:
- 메서드: GET, POST, HEAD 이외의 HTTP 메서드를 사용
- 헤더: Accept-Language, Accept, Content-Language 이외의 헤더를 포함
- Content-Type:
multipart/form-data
,application/x-www-form-urlencoded
,text/plain
이외의 콘텐츠 타입 사용
예를 들어, 데이터를 삭제하거나 수정하는 요청(예: DELETE, PUT 등)은 복잡한 요청으로 간주된다.
Preflight Request의 작동 방식
- 초기 OPTIONS 요청:
- 브라우저는 서버에 OPTIONS 요청을 보내서 허용 여부를 확인한다.
http코드 복사 OPTIONS /data HTTP/1.1 Origin: https://example.com Access-Control-Request-Method: DELETE
- 서버 응답:
- 서버는 클라이언트의 URL에서 허용할 수 있는 교차 출처 요청에 대한 정보를 응답 헤더에 포함하여 반환한다.
http코드 복사 HTTP/1.1 200 OK Access-Control-Allow-Origin: https://example.com Access-Control-Allow-Methods: GET, DELETE, HEAD, OPTIONS Access-Control-Allow-Headers: Content-Type
- Access-Control-Max-Age: 이 헤더는 브라우저가 프리플라이트 결과를 캐시할 수 있는 시간을 초 단위로 지정한다. 이를 통해 지정된 시간 동안 동일한 프리플라이트 요청을 반복할 필요 없이 여러 복잡한 요청을 보낼 수 있다.
CORS와 프론트엔드의 프록시 서버
프론트엔드 개발 시 프론트엔드 서버를 만들어서 백엔드 서버와 통신할 때 주로 CORS 에러를 마주치는데, 이를 해결하기 위해 프론트엔드에서 프록시 서버를 만들기도 한다.
프록시 서버 사용
- 방법 설명:
- 프록시 서버는 클라이언트와 API 서버 사이에 위치하여 요청을 중계한다.
- 클라이언트는 동일 출처 내의 프록시 서버에 요청을 보낸다. 프록시 서버는 이 요청을 실제 API 서버로 전달하고, 응답을 클라이언트에 반환한다.
- 구현 예시:
- 프록시 서버는 클라이언트와 동일한 도메인에 위치하거나, 서브도메인을 사용하여 동일 출처로 간주되도록 설정한다.
- 참고 - Proxy / CORS 정책 우회
참고
🌐 악명 높은 CORS 개념 & 해결법 - 정리 끝판왕 👏
도서 - 면접을 위한 CS 전공지식 노트, CORS와 프런트엔드의 프록시 서버