CORS(Cross-Origin Resource Sharing)는 서로 다른 Origin 간의 리소스 요청을 허용하기 위한 브라우저 기반의 보안 정책이다.
여기서 Origin은 다음 세 가지 조합으로 정의된다.
즉, 이 세 가지 중 하나라도 다르면 서로 다른 Origin으로 간주된다.
CORS는 서버 간 통신이 아니라 브라우저가 적용하는 보안 정책이라는 점이 핵심이다.
웹 애플리케이션 구조가 발전하면서 프론트엔드와 백엔드가 서로 다른 도메인에서 동작하는 경우가 많아졌다.
프론트엔드: https://frontend.com
백엔드 API: https://api.backend.com
이 상태에서 브라우저는 기본적으로 보안 정책인 Same-Origin Policy(SOP)에 의해 cross-origin 요청을 차단한다.
이러한 제한이 없을 경우 다음과 같은 문제가 발생할 수 있다.
CORS는 이러한 제한을 “선별적으로 허용”하기 위해 존재한다.
Same-Origin Policy는 브라우저 보안의 기본 원칙이다.
이 정책에 따르면, 동일한 Origin에서만 다음이 허용된다.
반대로 Origin이 다르면 요청 자체는 가능할 수 있지만, 응답 데이터를 JavaScript에서 읽는 것이 차단된다.
즉, SOP는 “요청 차단”이 아니라 “응답 읽기 차단”이라는 점이 중요하다.
CORS는 SOP의 예외 허용 규칙을 정의하는 메커니즘이라고도 볼 수 있다.
CORS는 요청을 두 가지 방식으로 처리한다.
다음 조건을 만족하면 Preflight 없이 바로 요청이 전송된다.
이 경우 브라우저는 바로 요청을 보내고, 서버의 응답 헤더를 보고 허용 여부를 판단한다.
조건을 만족하지 않는 요청은 먼저 OPTIONS 요청을 보낸다.
예를 들어 다음과 같은 경우이다.
흐름은 다음과 같다.
브라우저가 OPTIONS 요청 전송
서버가 허용 메서드 및 헤더 응답
허용된 경우 실제 요청 전송
즉, 실제 요청 전에 “허용 여부를 사전 확인” 하는 과정이다.
Preflight와 CORS는 별개다.
Preflight Request가 발생하지 않는다고 해서 CORS가 적용되지 않는 것은 아니다.
GET과 같은 Simple Request도 CORS 환경에서 동작하며, 응답에 적절한 CORS 헤더가 없으면 브라우저가 응답 접근을 차단한다.
Preflight Request는 CORS 환경에서 브라우저가 실제 요청을 보내기 전에 해당 Origin, 메서드, 헤더가 허용되는지 서버에 사전 확인하는 과정이다.
CORS는 CSRF 공격을 막기 위해 존재하는 것이 아니다.
CORS는 다른 Origin의 스크립트가 응답 데이터를 읽는 수 있는지만 제어할 뿐, 요청 전송 자체는 보호하지 않는다.
"다른 Origin의 JavaScript가 응답 데이터를 읽을 수 있는지 제어하기 위한 메커니즘" 이다.
CORS는 서버가 다음 헤더를 통해 정책을 결정한다.
Access-Control-Allow-Origin
→ 허용할 Origin 지정
Access-Control-Allow-Methods
→ 허용 HTTP 메서드 정의
Access-Control-Allow-Headers
→ 허용 헤더 정의
Access-Control-Allow-Credentials
→ 쿠키/인증 정보 허용 여부
Access-Control-Expose-Headers
→ 클라이언트에 노출할 응답 헤더 정의
Preflight는 다음 조건 중 하나라도 만족하면 발생한다.
GET/POST/HEAD 외의 메서드 사용
Authorization, X-Custom-Header 등 커스텀 헤더 사용
Content-Type이 application/json 등 단순하지 않은 경우
credentials 포함 요청
즉, “단순 요청이 아닌 경우” 모두 Preflight 대상이 된다.
CORS에서 인증 정보는 중요한 이슈이다.
또한 다음 조건이 필요하다.
CORS 에러는 대부분 서버 설정 문제이다.
대표적인 해결 방법은 다음과 같다.
프론트에서 해결할 수 있는 문제는 거의 없다.
혹은 Reverse Proxy를 적용해서 같은 Origin으로 만들고,
애초에 CORS 환경이 되지 않도록 만드는 방법도 있다.
혼동되지만 다른 것들
CORS (브라우저 정책)
Cross-Origin Resource Sharing
CSRF (요청 위조)
Cross-Site Request Forgery
XSS (스크립트 삽입)
Cross-Site Scripting
XSS는 내 컴퓨터(브라우저)에서 남의 스크립트가 내 정보를 훔쳐가는 것이고, CSRF는 내가 로그인한 은행이나 사이트 서버에 나쁜 짓(요청)을 몰래 시키는 것이다.
XSS 쿠키 및 세션 토큰 탈취, 개인정보 유출, 피싱이 목적인 클라이언트 대상 공격
CSRF 비밀번호 변경, 글 삭제, 불법 결제 등 권한 도용이 목적인 서버 대상 공격
CORS는 서버 간 통신 문제가 아니라 브라우저가 적용하는 보안 정책이다.
즉 정리하자면, CORS 문제를 해결하는 방법은
Preflight 자체의 이점이 있긴 하지만, 백엔드와 프론트엔드를 따로 구성할 땐 오히려 Preflight를 줄이는 게 성능을 개선하는 방향이라고 볼 수 있다.
프론트, 백엔드를 나눠서 개발을 진행할 땐 애초에 Reverse Proxy를 두어 같은 Origin처럼 보이게 구성해 CORS 환경이 아니게 만드는게 더 좋다고 생각한다.
약간의 복잡성이 추가되지만 단순히 백엔드에서 CORS를 신경쓰지 않아도 되는 개발 편의성 외로도 많은 장점이 있다.