Cross-Origin Resource Sharing (CORS) is an HTTP-header based mechanism that allows a server to indicate any origins (domain, scheme, or port) other than its own from which a browser should permit loading resources.
CORS(Cross-Origin Resource Sharing)는 웹개발자라면 한번쯤 겪는 오류에서 만나볼 수 있다. 이는 사실 SOP(Same-Origin Policy)이라는 정책으로부터 나오는 개념이다.
SOP는 어떤 origin(프로토콜 + ip주소 + 포트)에서 불러온 문서가 다른 origin의 리소스를 가져오는 방법을 제한하는 보안 메커니즘이다. 해당 보안 메커니즘을 검사하는 것은 클라이언트(웹 브라우저)이다!(그래서 서버끼리나 POSTMAN은 오류가 안뜬다..)
<!-- 해당 문서는 클라이언트가 http://example.com 에서 제공받은 상황 -->
<!-- Script로 다른 origin에 요청을 보냄 -> 클라이언트가 SOP에 따라 BLOCK -->
<script>
fetch("http://api.example.com/img.jpg", options)
.then((response) => console.log("response:", response))
.catch((error) => console.log("error:", error));
</script>
<!-- HTML Tag로 다른 origin에서 이미지 파일을 받아오려고 함 -> SOP 예외 즉 허용-->
<img src="http://api.example.com/img.jpg" />
<!-- 참고로 해당 요청은 Sec-Fetch-Mode: no-cors 값이 헤더에 들어가 보내지며 이를 통해서 예외처리를 해줌 -->
SOP는 악의적인 웹사이트가 브라우저에서 JS실행해 사용자가 로그인하고 있는 타사 웹메일이나 인트라넷에서 데이터를 읽고 공격자에게 전달하는 상황을 막아준다.
즉 SOP는 접속한 웹사이트 'example.com'이 아닌 클라이언트와 api.example.com의 데이터를 보호하기 위한 정책이다. 또한 CORS 오류는 SOP정책에 걸리는 상황에 해결책으로 CORS를 사용해보라는 내용이다.

SOP는 중요한 보안 정책이지만, 우리가 프론트서버와 백엔드가 존재하는 프로젝트를 만들었다고 생각해보자. 프론트서버는 백엔드에 데이터를 요청해서 직접 페이지를 제작하기도 하지만, 비동기적으로 JS를 통해 클라이언트에게 데이터를 요청하기도 한다. 이렇게 되면 당연히 프론트서버와 백엔드서버의 origin이 달랐을때 SOP를 위반한다. (우리가 아는 오류 발생)
따라서 SOP를 위반하지 않으려면 크게 두가지 방법을 사용한다.

앞서 SOP는 클라이언트와 'api.example.com'서버의 데이터를 보호하기 위한 정책이라고 했다. 그렇다면 예외처리 명시는 어디서 해줘야할까? 검사 실행은 클라이언트가 하니 당연히 검사 기준(예외 기준)은 'api.example.com'에서 제공해야한다. 때문에 CORS 설정은 백엔드 서버가 해결하는 경우가 많다.
기본적으로 백엔드 서버에 브라우저는 HTTP Header의 Origin 필드에 요청 출처를 담아 보낸다.
Request Header ------------
Origin: http://localhost:3000
이때 위 그림처럼 백엔드 서버는 응답으로 응답 헤더에 해당 리소스에 대한 접근을 허용하는 출처를 담는다.
Response Header ------------
Access-Control-Allow-Origin: 허용되는 origin 목록 (ex "https://example.com")
그 외에 속성들
Access-Control-Allow-Methods: 허용되는 메소드 (ex "GET, POST, OPTIONS")
Access-Control-Allow-Headers: 허용되는 헤더 목록 (ex "Authorization, Origin")
Access-Control-Allow-Credentials: 인증 헤더 사용가능여부 (ex true)
이후 브라우저가 두 값을 비교해서 Origin이 허용되는 출처라면 Response를 받아들인다. 이게 기본적인 흐름이다. 사실 CORS 동작 방식에는 3가지 시나리오가 있다.

가장 흔한 시나리오로 Preflight라는 예비 요청을 보내 CORS 설정이 되어있는지 먼저 확인하고 본 요청을 보내 데이터를 받아오는 방식이다.

대부분 Preflight Request를 사용하지만 밑과 같은 조건을 만족하면 바로 서버에 본요청을 보내고 CORS검사를 실시한다.
요청을 보낼때 인증정보를 제한하는 것으로 CORS의 기본적인 방식이 아니라 보안을 강화하고 싶을때 사용한다. 비동기 요청을 실시할때 비동기 리소스 요청 API인 XMLHttpRequest 객체나 fetch API는 인증관련 정보와 쿠키 정보를 헤더에 담지 않는다. 이때 요청에 인증과 관련된 정보를 담을 수 있게 해주는 옵션이 바로 credentials 옵션이다.
이 옵션은 총 3가지 값을 사용할 수 있다.
same-origin (기본값) : 같은 출처 간 요청에만 인증 정보를 담는다.
include : 모든 요청에 인증 정보를 담는다.
omit : 모든 요청에 인증 정보를 담지 않는다.
해당 설정은 프론트엔드에서 조절 가능하다. 예를 들어 이런식으로 요청을 명시할 수 있다.
fetch('http://localhost:4000/api', {
credentials: 'include',
});
만약 프론트엔드가 해당 설정을 적용했을 경우 백엔드서버는 밑의 두 가지 조건을 더욱 만족해야한다.
AOP를 지키면서 비동기 통신을 하는 방법이 있다.

기존엔 비동기통신을 다른 origin에 요청했기에 AOP 정책에 걸렸다.

이들 사이에 Proxy Server을 두고 모든 fetch 처리를 Proxy서버에서 다시 백엔드 서버로 전달하면 간단하게 해결가능하다. 여기에 백엔드 서버의 경우 프록시서버의 IP만 WhiteList를 적용한다던지 하는 방향으로 보안 강화도 가능하다.
CORS
https://medium.com/@lifthus531/cors%EC%97%90-%EB%8C%80%ED%95%9C-%EA%B9%8A%EC%9D%80-%EC%9D%B4%ED%95%B4-8c84c2137c83
https://developer.mozilla.org/ko/docs/Web/Security/Same-origin_policy
https://lo-victoria.com/introduction-to-cross-origin-resource-sharing-cors
https://evan-moon.github.io/2020/05/21/about-cors/