Foundry
네트워크
중급
핵심

CORS

교차 출처 리소스 공유, Preflight 요청

CORS (Cross-Origin Resource Sharing)

브라우저가 다른 출처(origin)의 리소스 요청을 제어하는 보안 메커니즘

출처(Origin)란?

https://api.example.com:443/users
└─┬──┘ └──────┬───────┘└┬─┘
프로토콜    호스트     포트

같은 출처: 프로토콜 + 호스트 + 포트 모두 동일
URL동일 출처?
https://example.com/a같은 출처. 경로만 다르다
http://example.com다른 출처. 프로토콜이 다르다
https://api.example.com다른 출처. 호스트가 다르다
https://example.com:8080다른 출처. 포트가 다르다

왜 필요한가?

[악성 사이트] evil.com
  ↓ 사용자 브라우저에서
  fetch('https://bank.com/transfer')
  ↓ 쿠키가 자동으로 포함됨!
  → CORS가 없으면 → 돈 이체 성공 😱
  → CORS가 있으면 → 브라우저가 차단 🛡️

동작 흐름

[단순 요청] (GET, 일부 POST)
Browser → Server
  Origin: https://app.com

Server → Browser
  Access-Control-Allow-Origin: *
  → 허용!

[Preflight 요청] (PUT, DELETE 등)
Browser → Server (OPTIONS)
  Origin: https://app.com
  Access-Control-Request-Method: PUT

Server → Browser
  Access-Control-Allow-Origin: ...
  Access-Control-Allow-Methods: PUT
  → OK면 실제 요청 진행

Preflight가 필요한 경우

조건단순 요청Preflight
GET, HEAD, POST해당
PUT, DELETE, PATCH해당
Content-Type: json해당
커스텀 헤더해당
Authorization 헤더해당

서버 설정 (응답 헤더)

Access-Control-Allow-Origin: https://app.com
Access-Control-Allow-Methods: GET, POST, PUT
Access-Control-Allow-Headers: Authorization
Access-Control-Allow-Credentials: true
Access-Control-Max-Age: 86400
헤더역할
Allow-Origin허용할 출처 (* 또는 특정)
Allow-Methods허용할 HTTP 메서드
Allow-Headers허용할 커스텀 헤더
Allow-Credentials쿠키/인증 포함 허용
Max-AgePreflight 캐시 시간

주의: Credentials + 와일드카드

동시에 쓸 수 없다:
Allow-Origin: *
Allow-Credentials: true

특정 출처를 명시해야 한다:
Allow-Origin: https://app.com
Allow-Credentials: true

실무 해결 패턴

상황해결
개발 중 CORS 에러프록시 설정 (Next.js rewrites)
API 서버미들웨어로 CORS 헤더 추가
특정 도메인만화이트리스트 방식
쿠키 기반 인증credentials + 특정 origin
CDN 리소스crossorigin 속성 추가
면접에서 이렇게 나옵니다

Q.CORS가 무엇이고 왜 필요한가요?

브라우저가 다른 출처의 응답을 스크립트에게 넘겨줄지 정하는 규칙입니다.

출처는 프로토콜, 호스트, 포트 셋이 모두 같아야 같습니다.

비교 대상같은 출처인가
https://example.com/a 와 /b같다. 경로만 다르다
http://example.com다르다. 프로토콜
https://api.example.com다르다. 호스트
https://example.com:8080다르다. 포트

기본 규칙(같은 출처 정책)이 없으면, 내가 방문한 악성 사이트의 스크립트가 내 은행 사이트에 요청을 보내고 응답을 읽을 수 있습니다. 쿠키가 자동으로 실리므로 로그인 상태 그대로입니다.

CORS 는 이 기본 금지를 서버가 명시적으로 푸는 방법입니다. 서버가 허용 헤더를 주면 브라우저가 응답을 넘겨줍니다.

흔한 실수: CORS 를 서버 보안 장치로 이해하는 것. 요청은 실제로 서버에 도착하고 처리됩니다. 브라우저가 응답 전달을 막을 뿐이라, 인증과 권한은 별도로 해야 합니다.

Q.Preflight 요청은 언제 발생하고 어떻게 동작하나요?

단순 요청이 아닌 경우 브라우저가 본 요청 전에 OPTIONS 로 먼저 물어봅니다.

조건단순 요청사전 확인 필요
메서드GET, HEAD, POSTPUT, DELETE, PATCH
Content-Type폼 형식이나 텍스트application/json
커스텀 헤더없음있음 (Authorization 포함)

사전 확인이 필요한 이유는 되돌릴 수 없는 요청을 먼저 막기 위해서입니다. DELETE 가 서버에 도착한 뒤 응답만 차단하면 이미 지워진 뒤입니다.

순서내용
OPTIONS 요청이 메서드와 헤더로 보내도 되는지 묻는다
서버 응답허용 출처, 허용 메서드, 허용 헤더, 캐시 시간
브라우저허용되면 본 요청을 보낸다

응답의 캐시 시간을 지정하면 매 요청마다 왕복이 생기는 것을 막을 수 있습니다.

흔한 실수: JSON 요청이 단순 요청이라고 답하는 것. Content-Type 이 application/json 이면 사전 확인 대상입니다.

Q.CORS 에러를 해결하는 방법을 설명해주세요.

서버에서 허용 헤더를 내려주는 것이 정석입니다. 클라이언트에서는 해결할 수 없습니다.

상황조치
기본 허용응답에 허용 출처 헤더를 넣는다
사전 확인 실패OPTIONS 에 허용 메서드와 헤더를 응답한다
쿠키를 함께 보냄자격 증명 허용을 켜고 출처를 정확히 명시한다
개발 환경프론트 개발 서버의 프록시로 같은 출처처럼 만든다
서버를 못 고칠 때우리 서버를 경유해 호출한다

마지막 두 가지는 우회입니다. 브라우저 확장으로 끄는 것은 개발자 본인 화면에서만 통하므로 해결이 아닙니다.

흔한 실수: 모든 출처를 허용해 버리는 것. 공개 읽기 전용 API 라면 괜찮지만, 인증이 있는 API 에 그렇게 하면 다른 사이트가 사용자 권한으로 응답을 읽을 수 있습니다.

Q.Access-Control-Allow-Credentials와 와일드카드의 제한은?

쿠키를 함께 보내는 요청에는 와일드카드를 쓸 수 없습니다.

설정자격 증명 없음자격 증명 있음
허용 출처와일드카드 가능정확한 출처를 명시해야 한다
허용 헤더와일드카드 가능명시해야 한다
허용 메서드와일드카드 가능명시해야 한다

이유는 명확합니다. 와일드카드와 쿠키를 함께 허용하면 어떤 사이트든 사용자의 로그인 상태로 우리 API 를 호출하고 응답을 읽을 수 있습니다. CSRF 에 응답 읽기까지 더해진 셈입니다.

그래서 서버는 요청의 Origin 헤더를 보고 허용 목록에 있으면 그 값을 그대로 반사해 응답합니다. 이때 목록 검증을 빠뜨리고 무조건 반사하면 와일드카드와 같아집니다.

흔한 실수: Origin 을 검증 없이 반사하고 자격 증명을 켜는 것. 설정상 와일드카드가 아니어서 통과하지만 실제 효과는 전면 허용입니다.

먼저 스스로 답해보고 아래 답변과 견줘보세요. 막히는 부분은 문제로 확인할 수 있어요.

더 깊이 공부하기

읽었으면 문제로 확인해보세요

네트워크 문제를 풀면 틀린 문제가 자동으로 노트에 쌓입니다. 가입 없이 5문제를 먼저 풀어볼 수도 있어요.