티스토리 뷰
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 같은 위험한 요청을 차단할 수 있다!
최신 웹 애플리케이션에서,
특히 SPA나 MSA 구조에서는 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
'Oops, All Code! > 📝 Study Notes' 카테고리의 다른 글
AJAX, 검색엔진이 싫어하는데 왜 개발자들은 계속 쓸까?👀 (0) | 2025.03.08 |
---|---|
웹 개발하면서 AJAX를 몰라도 되냐고요? 글쎄요…🤔 (0) | 2025.03.07 |
[Vue+TS] Vue 첫 만남, TypeScript로 만드는 랜덤 색상 생성기 (0) | 2024.12.02 |
[React+TS] 달력 기반 투두 리스트로 확장, UI/UX와 상태 관리의 조화 (0) | 2024.11.11 |
[React+TS] 투두리스트와 다크모드 결합을 통해 알아본 타입 좁히기 (0) | 2024.11.04 |
- Total
- Today
- Yesterday
- 소사벌
- 타입좁히기
- 대학생플리마켓
- 플리마켓운영
- 책추천
- 코딩테스트
- 프론트엔드
- 경험플리마켓
- 프로토타입
- 도서추천
- react
- 카드뉴스
- 소사벌맛집
- 카페추천
- 어른의어휘공부
- 트러블슈팅
- js
- 안성스타필드
- 프리코스
- javascript
- 비즈플리마켓
- typescript
- 우아한테크코스
- 대학생팝업스토어
- 회고
- 도서리뷰
- 일급객체
- 플리마켓후기
- 서평
- 어휘력
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |