티스토리 뷰

CORS는 보안 문제를 해결하기 위한 웹 브라우저 정책 중 하나이다.

웹 발전 과정에서 발생한 문제를 해결하기 위해 등장한 메커니즘이다.

 

이를 이해하기 위해서 선행되는 개념은 바로 SOP다.

웹이 처음 만들어졌을 때 보안 개념이 약했기 때문에 이러한 문제가 발생했기 때문이다.

💡 악성 웹사이트가 다른 사이트의 데이터를 무단으로 요청
 - 앨리스 은행에 로그인한 상태에서 악성 웹사이트인 밥이 앨리스에게 API를 몰래 요청했다.

 

이런 공격을 방지하기 위해 브라우저가 기본적으로 다른 출처의 리소스를 가져오는 것

차단하는 동일 출처 정책(SOP)이 등장했다.

 

SOP(Same-Origin Policy)란?

 

브라우저는 현재 방문 중인 웹사이트에서만 데이터를 요청할 수 있도록 제한하는 정책

 

🔥 동일 출처(Same-Origin)의 기준은?

출처는 3가지 요소가 모두 같아야 동일하다고 판단한다.
  - 프로토콜 http://, http://
  - 호스트 mindaaaa.com
  - 포트 (생략 가능) :80, :443, :8080

 

하지만 이 방식은 웹 개발에 불편함을 초래하게 됐다.

 

몇 가지 한계점이 있었기 때문인데,

가장 먼저 웹이 발전하면서 다른 도메인의 API를 사용해야 하는 경우가 증가했다.

☁️ https://mindaaa.com에서 https://api.weather.com의 날씨 정보를 원할 때

 

CDN에서 정적 리소스를 로드해야하는 경우도 있다.

웹사이트가 https://mindaaaacdn에서 이미지를 불러오려는 시도를 하면 차단된다.

🔥 CDN이란?
 CDN은 정적 리소스를 빠르게 제공하는 서버 네트워크다.
 다음과 같은 이유로 웹사이트에 더 빠르고, 안정적으로 동작한다.

 - 여러 개의 서버(노드)를 사용해 지연 시간이 줄어든다.
 - 자주 요청되는 정적 리소스는 캐싱하기 때문에 반복 요청에 빠르게 대응한다.
 - 원래 서버의 부담이 줄어든다.

 

또, 백엔드가 여러 도메인으로 나뉘어 있을 때도 SOP에 의한 차단이 일어난다.

브라우저에서 서로 다른 도메인의 API를 호출하면 문제가 발생한다.

 

프론트엔드 애플리케이션이 아래 API와 통신한다고 가정해보자.

서비스 역할 도메인
인증 서비스 로그인, 회원가입 관리 https://auth.service.com
데이터 서비스 사용자 데이터 관리 https://data.service.com
결제 서비스 결제 및 구독 관리 https://payment.service.com

 

브라우저는 현재 열려 있는 웹사이트에서만 API 요청을 허용하기 때문에

브라우저는 https://auth.service.com의 요청을 차단한다.

 

이러한 배경 속에 CORS(Cross-Origin Resource Sharing)가 등장하게 된다.


CORS의 등장
💡 서버가 특정 도메인에 대한 접근을 허용하도록 명시적으로 설정

 

CORS는 안전한 범위 내에서 교차 출처 요청을 허용하는 메커니즘이다.

서버가 특정 출처를 허용하면 브라우저는 요청을 진행한다.

✅ CORS의 핵심 개념

서버는 특정 출처에서 오는 요청만 허용 가능하다.
이때 HTTP 메서드나 헤더 등의 제한을 세밀하게 설정 가능하다.

인증이 필요한 경우 Access-Control-Allow-Credentials를 true로 설정하면 된다.

 

🔥 CORS의 동작 원리

CORS를 한 문장으로 정리하면 클라이언트(브라우저) → 서버 간의 요청이 차단되지 않도록 하는 방법이다.

📍 CORS의 핵심 동작 과정
  1. 브라우저가 교차 출처 요청을 보냄
  2. 서버가 CORS 관련 헤더를 포함한 응답을 보냄
  3. 브라우저가 서버의 응답을 확인 후 요청에 대한 응답을 결정함

 

이러한 요청 방식에는 2가지 유형이 있다.

💡 CORS 요청 방식
1. Simple Request → 사전 검사 없이 바로 요청한다.
2. Preflight Request → OPTIONS 요청을 먼저 보내서 허용 여부를 확인한다.

🚀 1. Simple Request (단순 요청)

 

아래 조건을 모두 만족하면 브라우저가 사전 검사 없이 바로 요청을 보낸다.

✅ Simple Request 조건

- GET, POST, HEAD 메서드만 사용 가능
- Content-Type이 다음 중 하나만 가능
    application/x-www-form-urlencoded
    multipart/form-data
    text/plain
- Authorization 헤더 같은 추가 커스텀 헤더를 포함하지 않음
- 요청이 XMLHttpRequest 또는 fetch()로 보내짐

 

예를 들어 이런 식으로 동작한다.

 

먼저, 브라우저에서 서버로 요청을 보낸다.

GET /data HTTP/1.1
Host: api.example.com
Origin: https://mindaaaa.com

 

서버가 CORS 허용 헤더를 포함해 응답한다.

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://mindaaaa.com
Content-Type: application/json

 

브라우저가 Access-Control-Allow-Origin 헤더를 확인해 요청을 허용한다.


🚀 2. Preflight Request (사전 검사 요청)

 

브라우저가 먼저 허용되는지를 확인하는 요청이다.

OPTIONS 메서드를 이용해 특정 요청을 허용하는지 미리 확인한다.

 

예를 들어보자.

먼저, 브라우저가 OPTIONS 요청을 보낸다.

OPTIONS /data HTTP/1.1
Host: api.example.com
Origin: https://mindaaaa.com
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Authorization, Content-Type
👩‍💻 무슨 의미일까?

Origin : 요청을 보낸 클라이언트 주소
Access-Control-Request-Method : 클라이언트가 보내려는 HTTP 메서드 POST
Access-Control-Request-Header : 클라이언트가 포함하려는 추가 헤더 Autorization

 

서버가 허용하는 경우 CORS 헤더를 포함한 응답을 보낸다.

HTTP/1.1 204 No Content
Access-Control-Allow-Origin: https://mindaaaa.com
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: Authorization, Content-Type
Access-Control-Max-Age: 86400
👩‍💻 무슨 의미일까?

Access-Control-Allow-Origin : 요청을 허용하는 출처
Access-Control-Allow-Methods : 허용할 HTTP 메서드
Access-Control-Allow-Headers : 허용할 요청 헤더
Access-Control-Max-Age : 캐시 유지 기간 이 시간동안 Preflight 요청을 다시 보내지 않음

 

그럼 브라우저가 응답을 확인하고 서버가 허용했다면 실제 요청을 보낸다.

POST /data HTTP/1.1
Host: api.example.com
Origin: https://mindaaaa.com
Authorization: Bearer token123
Content-Type: application/json

 

마지막으로 서버가 응답을 보내면

브라우저는 API 요청이 안전하다고 판단해 데이터를 가져올 수 있다.

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://mindaaaa.com
Content-Type: application/json

 

대부분의 경우 Preflight Request를 이용한다는데

사전 검사를 추가하는 게 왜 유의미할까?

오히려 필요없는 자원을 낭비하는 것은 아닐까?


👀 Preflight Request가 유의미한 이유

 

먼저 불필요한 API 요청을 방지할 수 있다.

Preflight를 통해 서버가 모든 요청에 응답하지 않아도 된다.

 

허용되지 않는 요청은 미리 차단하고 서버 리소스를 낭비하지 않아도 되기 때문에

악성 사이트에서 API를 무작위로 호출하는 것을 방지할 수 있다.

💡 API 남용을 막아보자

OPTIONS
메서드로 허용 여부를 확인한다.
허용되지 않으면 실제 API 요청을 차단한다. 403 FOrbidden
OPTIONS /user-data HTTP/1.1
Origin: https://unknown.com
Access-Control-Request-Method: GET
HTTP/1.1 403 Forbidden
Access-Control-Allow-Origin: https://mindaaa.com

 

또, 서버가 허용하는 요청을 명확하게 설정할 수 있다.

특정 요청만 허용해 보안을 강화하는 데 도움이 된다.

Access-Control-Allow-Methods: POST, GET
Access-Control-Allow-Headers: Authorization, Content-Type

 

 

이런 설정을 통해 PUT, DELETE 같은 위험한 요청을 차단할 수 있다!

 

최신 웹 애플리케이션에서,

특히 SPAMSA 구조에서는 API 요청이 많아지는데

Preflight 요청을 통해 보안과 성능을 균형 있게 유지할 수 있다.

여러 개의 API 서버를 호출할 때 서버가 허용한 요청만 수행 가능 auth.mindaaa.com data.mindaaa.com
API Gateway 같은 곳에서 Preflight 요청을 처리하면 보안성과 확장성이 높아짐
🔥 SPA(Single Page Application)와 MSA(Microservices Architecture) 간단 정리
- SPA는 웹사이트의 동작 방식
- MSA는 백엔드 아키텍처 구조

SAP
한 개의 HTML 파일에서 모든 페이지를 동적으로 관리하는 웹 애플리케이션
새로고침 없이 화면을 업데이트한다!

MSA
하나의 거대한 서비스를 여러 개의 작은 서비스로 분리하는 아키텍처

출처

 

zettelkasten/3.Resource/Zettelkasten/3.Permanent/CORS란? at master · injuk/zettelkasten

zettelkasten(사실 아님). Contribute to injuk/zettelkasten development by creating an account on GitHub.

github.com

 

댓글