PromleeBlog
sitemap
aboutMe

posting thumbnail
CORS 동작 원리와 핵심
A Deep Dive into How CORS Works

📅

🚀

들어가기 전에 🔗

이번 시간에는 프론트엔드 개발을 하다 보면 반드시 마주치게 되는 붉은색 에러 메시지의 주범, 바로
CORS(Cross-Origin Resource Sharing)
에 대해 깊이 있게 알아보겠습니다.
많은 개발자들이 CORS 오류를 만나면 급하게 서버 코드에 Access-Control-Allow-Origin: *를 추가하고 넘어가곤 합니다.

하지만 CORS는 귀찮은 에러가 아니라, 우리의 웹 애플리케이션을 안전하게 지켜주는 중요한
보안 정책
입니다.
오늘은 CORS가 왜 필요한지 그 근본적인 이유부터 시작하여, 브라우저가 내부적으로 어떻게 이 정책을 처리하는지 그 동작 원리를 낱낱이 파헤쳐 보겠습니다.

🚀

보안의 대원칙: 동일 출처 정책 (SOP) 🔗

CORS를 이해하려면, 먼저 브라우저의 가장 기본적인 보안 규칙인
동일 출처 정책(SOP, Same-Origin Policy)
을 알아야 합니다.

SOP는 말 그대로,
'같은 출처(Origin)에서 온 리소스만 공유할 수 있다'
는 정책입니다.
여기서 '출처'란 URL의
프로토콜(Protocol), 호스트(Host), 포트(Port)
세 가지를 모두 합친 것을 의미합니다.
이 세 가지 중 하나라도 다르면, 브라우저는 두 출처가 서로 다르다고 판단합니다.

예를 들어 https://my-domain.com에서 다른 곳으로 요청을 보낼 때,

이 정책이 없다면, 만약 여러분이 악성 사이트에 접속했을 때 그 사이트의 스크립트가 여러분의 은행 사이트에 멋대로 요청을 보내 개인정보를 탈취하는 끔찍한 일이 벌어질 수 있습니다.
SOP는 이렇게 다른 출처의 리소스를 함부로 읽어오지 못하게 막아주는 아주 중요한 보안 장벽입니다.

🚀

SOP의 예외 허용: CORS (교차 출처 리소스 공유) 🔗

SOP는 보안에 필수적이지만, 현대 웹 개발에서는 API 서버를 별도로 두는 등 다른 출처의 리소스가 필요한 경우가 아주 많습니다.

CORS
는 바로 이럴 때를 위해 만들어진 정책입니다.
CORS는 SOP라는 보안 원칙을 지키면서도,
서버와 클라이언트가 서로 합의하여 안전하게 다른 출처의 리소스를 공유할 수 있도록 허용해주는 메커니즘
입니다.

중요한 점은, CORS는
서버
가 설정하는 정책이라는 것입니다.
서버가 자신의 응답 헤더에 Access-Control-Allow-Origin과 같은 특정 정보를 담아 보내주면, 브라우저는 이 헤더를 보고 "아, 이 서버는 다른 출처의 요청을 허용하는구나"라고 판단하고 리소스 접근을 허락해 줍니다.
CORS 에러는 서버가 허락하지 않았는데 브라우저가 막는 상황이므로, 해결은 항상 서버 측에서 이루어져야 합니다.

🚀

CORS의 동작 방식 🔗

브라우저는 모든 교차 출처 요청을 똑같이 처리하지 않습니다.
요청의 '위험도'에 따라 두 가지 다른 시나리오로 나누어 처리하는데, 이것이 CORS를 이해하는 핵심입니다.

1. 단순 요청 (Simple Request) 🔗

마치 간단한 소포를 보내는 것처럼, 서버에 별다른 영향을 주지 않을 것이라고 판단되는 '안전한' 요청들입니다.
아래 세 가지 조건을 모두 만족해야 합니다.


동작 흐름
  1. 브라우저는 일단 서버로 실제 요청을 바로 보냅니다.
  2. 서버는 요청을 받고, 응답 헤더에 Access-Control-Allow-Origin: https://my-domain.com 과 같은 헤더를 포함하여 응답합니다.
  3. 브라우저는 서버의 응답 헤더를 확인합니다.
    Access-Control-Allow-Origin 헤더가 있고, 그 값이 현재 사이트의 출처와 일치하면, 응답을 자바스크립트 코드로 전달합니다.
  4. 만약 헤더가 없거나 출처가 일치하지 않으면, 브라우저는 응답을
    차단
    하고 콘솔에 CORS 에러를 표시합니다. (중요: 요청은 이미 서버에 도달했습니다!)

2. 프리플라이트 요청 (Preflight Request) 🔗

단순 요청의 조건을 만족하지 않는, 서버의 데이터에 영향을 줄 수 있는 '잠재적으로 위험한' 요청들입니다.
(예: PUT, DELETE 메서드, Content-Type: application/json, 커스텀 헤더 포함 등)

이 경우 브라우저는 실제 요청을 보내기 전에, 먼저
프리플라이트(Preflight)
라는 예비 요청을 보내 서버의 허락을 구합니다.
마치 중요한 손님이 방문하기 전에, 비서가 먼저 전화를 걸어 "이런 분이 이런 용무로 방문해도 괜찮을까요?"라고 물어보는 것과 같습니다.

동작 흐름
  1. 브라우저는 실제 요청을 보내기 전에, 먼저 OPTIONS라는 HTTP 메서드를 사용하여 예비 요청(프리플라이트)을 서버에 보냅니다.
    이 예비 요청에는 앞으로 보낼 실제 요청의 메서드(Access-Control-Request-Method)와 헤더(Access-Control-Request-Headers) 정보가 담겨있습니다.
  2. 서버는 이 OPTIONS 요청을 받고, 자신의 CORS 정책에 따라 어떤 메서드와 헤더를 허용하는지 응답 헤더(Access-Control-Allow-Methods, Access-Control-Allow-Headers 등)에 담아 응답합니다.
  3. 브라우저는 이 프리플라이트 응답 헤더를 확인합니다.
    만약 서버가 앞으로 보낼 실제 요청을 허용한다고 판단되면,
    그때서야 실제 요청(예: PUT 요청)을 서버에 보냅니다.
  4. 만약 서버가 허용하지 않으면, 브라우저는 실제 요청을 보내지 않고 CORS 에러를 표시합니다.
Preflight Request Flow
Preflight Request Flow

🚀

주요 면접 예상 질문 🔗

CORS의 동작 원리는 웹 보안의 기본이므로, 면접에서 그 이해도를 확인하는 질문이 자주 나옵니다.

1. CORS가 무엇이고, 왜 필요한가요? 🔗

이 질문은 SOP와의 관계를 함께 설명하는 것이 핵심입니다.
CORS는 교차 출처 리소스 공유 정책으로, 브라우저의
동일 출처 정책(SOP)
이라는 보안 규칙 때문에 필요합니다.
SOP는 기본적으로 다른 출처의 리소스 요청을 차단하여 보안을 지키지만, 현대 웹에서는 API 서버 분리 등 다른 출처의 리소스가 필요한 경우가 많습니다.
CORS는 서버가 특정 다른 출처를 신뢰한다고 명시적으로 알려주어, 브라우저가 안전하게 SOP의 예외를 허용하도록 만드는 메커니즘입니다.

2. 프리플라이트 요청은 무엇이고, 언제 발생하나요? 🔗

단순한 개념을 넘어, 내부 동작 원리를 깊이 있게 이해하고 있는지 확인하는 질문입니다.
프리플라이트 요청은 브라우저가 실제 요청을 보내기 전에 서버가 해당 요청을 허용하는지 미리 확인하는
예비 요청
입니다.
이 요청은 HTTP의 OPTIONS 메서드를 사용합니다.
단순 요청(Simple Request)의 조건을 벗어나는, 예를 들어 PUT이나 DELETE 메서드를 사용하거나, Content-Typeapplication/json이거나, 커스텀 헤더가 포함된 요청을 보낼 때 발생합니다.
서버가 이 OPTIONS 요청에 대해 허용한다는 응답을 보내야만, 브라우저는 비로소 실제 요청을 서버로 보냅니다.

3. CORS 문제를 프론트엔드에서 해결할 수 있나요? 🔗

이 질문은 문제 해결의 책임 소재를 명확히 알고 있는지 확인합니다.
원칙적으로 CORS는 브라우저가 서버의 응답 헤더를 보고 판단하는 정책이므로, 근본적인 해결은
서버 측에서
이루어져야 합니다.
서버의 응답 헤더에 Access-Control-Allow-Origin과 같은 올바른 CORS 관련 헤더를 추가해 주어야 합니다.
물론 개발 환경에서는 프록시 서버를 사용하여 요청의 출처를 속이는 방식으로 우회할 수는 있지만, 이는 임시방편일 뿐 실제 프로덕션 환경에서의 해결책은 아닙니다.

🚀

결론 🔗

오늘은 웹 보안의 핵심인 CORS에 대해 깊이 있게 알아보았습니다.

참고 🔗