개발을 하다 보면 한 번쯤은 CORS 정책 위반 이슈를 마주치게 된다.
이를 해결하기 위해서는 프록시 서버가 필요하다는 말을 듣곤 하는데,
정확히 CORS가 무엇인지, 어떻게 해결하는지에 대해 알아보자.
먼저 CORS 란 'Corss-Origin Resource Sharing'의 약자로 '교차 출처 자원 공유' 정책이다. 이때 '출처'란 무엇일까 ?
출처(origin)
: URL을 구성하며protocol,host,port를 조합한 것
출처란 URL(uniform resource locator) 안에 포함되는 개념으로 볼 수 있으며
프로토콜, 호스트, 포트번호를 조합한 것이다.
location.origin으로 확인 가능출처는 웹 상에서 '어디에서 왔는지' 를 나타내는 주소의 일부분이며 url의 시작부분이라고 보면 이해가 쉽다. 우리가 사용하는 url은 출처 정보에 경로(path), 쿼리 스트링(query string)이 포함된 정보라고 볼 수 있다.
예를 들면 url은 https://www.example.com/users/profile?id=123 이런식으로 origin에 부가적인 정보를 넣어 사용한다. (포트 번호는 생략되기도 한다.)
🔻 프로토콜(Protocol)
: 웹에서 데이터를 주고 받을 때 사용하는 통신규약으로 http, https 가 있다.
http에 secure(보안)이 붙은 것이 https이며 https는 데이터를 암호화 (로그인 등 개인 정보에 필수)해서 사용한다. 보안이 중요시 되며 요즘 대부분은 https를 사용하고 브라우저 주소창에 자물쇠 모양 아이콘 🔐이 있다면 https 를 쓰고 있다는 뜻 !
🔻 호스트(Host)
: 네트워크에 연결되어 통신하는 컴퓨터 또는 장치
각 호스트는 네트워크에서 고유하게 식별되어야 하는데 이때 IP주소 (Internet Protocol Address)나 호스트 이름(Host Name)을 사용하여 식별한다. IP 주소는 192.168.1.1 같은 숫자 주소이고, 호스트 이름은 www.example.com 같은 사람이 읽기 쉬운 이름이다.
🔻 포트 번호(Port)
: 호스트 내에서 실행되고 있는 특정 애플리케이션 프로세스나 서비스를 구분하기 위해 사용하는 번호
하나의 호스트(컴퓨터)에는 여러 개의 프로그램이 동시에 돌아간다. 이때 특정 포트 번호를 지정해서 요청을 보내면 호스트는 해당 포트 번호에서 실행 중인 프로그램으로 요청을 전달해준다.
즉 네트워크 통신은 기본적으로 '어떤 호스트의 어떤 포트 번호로' 데이터를 보낼지를 지정해서 이루어진다 !
SOP (Same-Origin Policy)
: 동일 출처 정책
우리가 사용하는 브라우저는 기본적으로 SOP(Same-Origin Policy)를 사용하고 있다. 동일한 출처 간의 리소스 공유가 가능하다는 보안 정책이며 이는 악성 사이트로부터 사용자를 보호하기 위한 정책이라고 볼 수 있다. 우리의 브라우저는 이 SOP을 통해 동일한 origin 사이의 요청을 허락하고 다른 origin 사이의 요청은 막고 있는 것이다. 예를 들어보겠다.
사용자가 악성 사이트에 접속했을 때, 그 페이지에 있는 악성 스크립트가 사용자의 브라우저에서 돌아가게된다. 이 스크립트가 사용자의 브라우저를 이용해서 은행 사이트로 돈 이체 같은 요청을 보내려고 한다고 가정해보자. 이때 '악성 스크립트가 돌아가는 페이지의 출처 (http://bad-site.com)'와 '요청을 보내려는 목표 사이트의 출처 (https://bank.com)'가 다르기 때문에, 브라우저의 SOP이 작동해서 해당 사항을 차단하고 사용자를 보호하게 된다.
CORS (Cross-Origin Resource Sharing)
: SOP 때문에 차단되는 교차 출처 요청을 안전하게 허용할 수 있도록 하는 메커니즘
개발을 하다보면 보통 클라이언트와 서버로 나누어 작업을 하게된다. 같은 로컬(호스트)에서 작업하더라도 클라이언트와 서버는 포트 번호가 다르기 때문에 출처가 달라진다. 보통 서버에서 데이터를 받아 클라이언트에 띄워야하는데 서버와 클라이언트는 출처가 다르므로 이때 발생하는 문제가 SOP(에 의한 해당 요청 차단)이며, 그때 뜨는 빨간 오류 문장이 CORS(해결 방안)를 사용하라는 것이라고 보면 된다.
정리해보자면, 우리는 CORS 때문에 오류가 발생한다고 생각하지만 사실은 아니다.
우리가 해결해야 할 문제는 SOP(Same-Origin Policy) 이며, 이 SOP을 해결 할 수 있는 방법이 CORS인 것이다..!
복잡해보일 수 있지만 이해하면 생각보다 쉬운 내용이다. SOP과 CORS가 모두 필요한 이유는 브라우저가 악성 사이트로부터 사용자를 보호하기 위해 기본적으로 교차 출처 요청을 차단하기 위해 'SOP'이 필요하고, 이를 유지하면서도 현대 웹 앱의 필수적인 요구사항인 다른 출처 간 리소스의 안전한 상호작용을 가능하게 하기 위해 'CORS'가 필요하다고 볼 수 있다.
CORS 에러 발생 이유
CORS 에러 해결 방법
그렇다면 CORS 에러가 떴을 때 해결 방법은 무엇일까 ? 대표적으로 2가지를 꼽을 수 있다.
Access-Control-Allow-Origin 헤더 추가서버에서 응답을 보낼 때 'Access-Control-Allow-Origin: 허용할 출처'를 기재할 수 있다. 허용할 출처 부분에 응답을 보낼 출처를 적어 보내면 브라우저에서는 해당 출처를 안전하다고 판단하여 SOP 정책이 실행되지 않는다.
프론트엔드와 백엔드 서버가 다른 출처일 때, 그 사이에 프록시 서버를 두는 방법이 있다. 프록시 서버는 소프트웨어를 설치하는 방법도 있지만 보통 웹 개발 프레임워크나 도구에서 제공하는 개발용 프록시 기능을 쓰는 경우가 많다.
프론트엔드는 같은 출처인 프록시 서버에 요청 → 프록시 서버가 백엔드에 요청해서 응답을 받아 다시 프론트엔드로 넘겨줌
프록시 서버는 프론트엔드와 동일한 출처를 갖기에 프론트와 통신이 가능하고, 서버끼리의 통신에서는 브라우저가 개입하지 않기 때문에 SOP이 적용되지 않는다. 결국 이렇게 하면 브라우저 입장에서는 같은 출처끼리 통신하는 것처럼 보여서 SOP에 걸리지 않는 것이다.

예시로 CORS 에러를 내왔다. 현재 velog 포스트에서 개발자도구를 열고 https://example.com 이라는 임의의 다른 출처 리소스를 요청하는 코드이다. 첫번째 에러에서 CORS 에러를 확인할 수 있다.
Access to fetch at from origin 'https://velog.io' has
been blocked by CORS policy: No 'Access-Control-Allow-Origin'
header is present on the requested resource.
이 메시지는 요청한 리소스가 CORS 정책에 의해 차단되었음을 나타내며, 요청한 출처(https://velog.io)가 해당 리소스에 접근할 수 있는 권한이 없다는 의미이다. 그 뒤로는 요청한 리소스에서 CORS 헤더가 설정되어 있지 않음을 나타내고 있다. 서버가 특정 출처에서의 요청을 허용하도록 'Access-Control-Allow-Origin' 헤더를 설정해주면 해결이 가능하다.
(그 아래의 오류는 404 오류(Not Found)로 해당 리소스가 존재하지 않음을 뜻한다.)
: 본 요청 전에 서버에 허락을 받는 예비 요청
주로 CORS를 사용하는 상황에서 발생하며, 클라이언트가 서버에 어떤 요청을 보내기 전에 OPTIONS 메서드를 사용해서 서버에 물어보는 과정이다.
Preflight 요청의 흐름을 보자면 클라이언트가 서버에 OPTIONS 메서드를 사용하여 Preflight 요청을 보낸다. 서버는 요청을 분석하고, 해당 요청을 허용할지 여부를 결정한다. 서버가 요청을 허용하면, 클라이언트는 본 요청을 진행하게 된다.
장점으로는 보안 강화가 있다.
Preflight 요청을 통해 클라이언트는 서버가 허용하는 출처와 메서드를 확인할 수 있다. 이를 통해 악의적인 요청을 사전에 차단할 수 있으므로 보안이 강화되는 효과를 볼 수 있다.
단점으로는 성능 저하가 있다.
Preflight 요청이 추가로 발생하기 때문에, API 호출 수가 2배로 늘어나는 문제가 있다. 클라이언트가 실제 요청을 보내기 전에 먼저 Preflight 요청을 보내야 하므로 성능이 2배로 저하될 수 있는 것이다.