gemini와 cors 이해하기

edward·2026년 3월 6일

웹에서 cors가 뭐야?

CORS (Cross-Origin Resource Sharing) 이해하기

CORS는 웹 브라우저에서 실행되는 스크립트가 다른 도메인(출처)의 자원에 접근할 수 있는 권한을 부여하도록 브라우저에 알려주는 체제입니다.

기본적으로 웹 브라우저는 보안상의 이유로 SOP (Same-Origin Policy, 동일 출처 정책)를 따릅니다. 이는 자바스크립트가 자신이 로드된 도메인과 다른 도메인으로 HTTP 요청을 보내는 것을 제한하는 규칙입니다. 하지만 현대 웹 개발에서는 API 서버와 프론트엔드 서버가 분리된 경우가 많아, 이를 안전하게 허용하기 위해 CORS가 사용됩니다.

1. '출처(Origin)'의 기준

브라우저는 다음 세 가지 요소가 모두 일치해야 동일한 출처로 판단합니다.

  • Protocol (http, https)
  • Host (domain.com, localhost)
  • Port (80, 443, 3000)

예를 들어, https://naver.com에서 https://api.naver.com으로 요청을 보내면 호스트가 다르기 때문에 CORS 정책의 적용을 받게 됩니다.

2. CORS의 작동 방식

CORS는 HTTP 헤더를 통해 작동하며, 크게 두 가지 요청 방식으로 나뉩니다.

단순 요청 (Simple Request)

다음 조건을 만족하는 경우, 브라우저는 바로 본 요청을 보냅니다.

  • 메서드가 GET, POST, HEAD 중 하나일 것
  • 헤더가 Accept, Content-Language 등 기본적인 것만 포함될 것

예비 요청 (Preflight Request)

대부분의 현대적인 API 요청(JSON 데이터 전송 등)은 이 방식에 해당합니다.

  1. OPTIONS 메서드를 사용하여 본 요청을 보내기 전, 서버에 "내가 이런 요청을 보내도 되니?"라고 먼저 물어봅니다.
  2. 서버는 응답 헤더에 허용되는 출처(Access-Control-Allow-Origin) 등을 담아 보냅니다.
  3. 브라우저가 응답을 확인하고 안전하다고 판단하면 그제야 진짜 요청을 보냅니다.

3. 주요 응답 헤더

서버 측에서 CORS 문제를 해결하기 위해 설정해야 하는 핵심 헤더들입니다.

헤더설명
Access-Control-Allow-Origin자원 접근이 허용된 출처를 지정합니다. (예: * 또는 https://my-site.com)
Access-Control-Allow-Methods허용되는 HTTP 메서드 목록을 지정합니다. (GET, POST, PUT 등)
Access-Control-Allow-Headers실제 요청 시 사용할 수 있는 HTTP 헤더를 지정합니다.
Access-Control-Allow-Credentials쿠키나 인증 정보를 포함한 요청을 허용할지 여부를 결정합니다.

4. 흔히 발생하는 오해

  • 서버 간 통신에는 해당되지 않음: CORS는 웹 브라우저가 강제하는 보안 정책입니다. 따라서 서버(Node.js, Java 등)에서 다른 서버로 요청을 보낼 때는 발생하지 않습니다.
  • 서버는 요청을 수행할 수도 있음: 브라우저가 응답을 차단하는 것이지, 서버가 요청을 아예 안 받는 것은 아닙니다. 서버 로그에는 성공으로 뜨는데 브라우저 콘솔에서만 에러가 날 수 있습니다.

cors가 왜 보안이랑 연결되는 거지??

SOP(Same-Origin Policy, 동일 출처 정책)가 보안의 핵심인 이유는 간단합니다. "내가 로그인한 A 사이트의 권한을 B 사이트가 마음대로 가로채지 못하게 하기 위해서"입니다.

만약 SOP가 없다면, 여러분이 브라우저에서 탭을 여러 개 띄워놓고 사용하는 것 자체가 매우 위험한 일이 됩니다.

1. SOP가 막아주는 핵심 공격: CSRF (사이트 간 요청 위조)

가장 대표적인 시나리오는 다음과 같습니다.

  1. 상황: 여러분이 bank.com(은행 사이트)에 로그인되어 있고, 브라우저에는 해당 사이트의 로그인 세션(쿠키)이 남아 있습니다.
  2. 공격: 이때 피싱 메일 등을 통해 악성 사이트인 evil.com에 접속하게 됩니다.
  3. 실행: evil.com의 자바스크립트가 배경에서 몰래 bank.com/transfer?to=attacker&amount=10000이라는 요청을 보냅니다.
  4. 결과: 브라우저는 bank.com으로 요청을 보낼 때 저장된 쿠키(인증 정보)를 함께 실어 보냅니다. SOP가 없다면 은행 서버는 "오, 정당한 사용자가 돈을 보내라고 했네?"라고 판단하여 송금을 처리해 버립니다.

2. 정보 유출 방지 (Data Privacy)

SOP는 단순히 '요청'을 막는 것뿐만 아니라, '응답 데이터에 접근하는 것'을 막습니다.

  • naver.com에 접속 중인 상태에서 다른 탭으로 들어간 malicious-site.com이 자바스크립트를 이용해 naver.com/my-profile의 내용을 읽어오려 한다고 가정해 봅시다.
  • SOP가 적용되어 있다면, 브라우저는 출처(Origin)가 다르다는 것을 확인하고 malicious-site.com이 네이버 서버로부터 온 응답 데이터를 읽지 못하도록 차단합니다.
  • 이 정책 덕분에 개인 정보나 이메일 내용 등이 다른 사이트의 스크립트에 의해 노출되지 않습니다.

3. 브라우저의 '샌드박스' 역할

웹 브라우저는 수많은 서로 다른 서비스들이 한 공간(브라우저)에서 실행되는 환경입니다. SOP는 각 웹사이트가 자신만의 독립된 보안 구역(Sandbox) 안에서만 놀 수 있도록 벽을 세우는 역할을 합니다.

  • 벽이 없다면: 웹은 무법천지가 되어, 어떤 사이트를 방문하든 내 브라우저에 열려 있는 다른 모든 사이트의 정보를 털어갈 수 있게 됩니다.

요약하자면

SOP는 브라우저 차원의 최소한의 방어선입니다.

  1. 누가 나인 척하는 것(요청 위조)을 어렵게 만들고,
  2. 내 정보를 훔쳐보는 것(데이터 탈취)을 원천 봉쇄합니다.

CORS는 바로 이 엄격한 보안 벽(SOP)에 "이 사이트는 믿을 만하니까 우리가 정한 규칙 하에 벽을 살짝 열어주자"라고 예외를 두는 허가증 같은 개념인 셈입니다.

그럼 cors를 허용해주는건 특정 서버에서 다른 서버를 믿을 수 있다고 등록해줘야 가능한건가?? 그러니까 예를 들어서 edward_giver 서버에서 edward_taker 서버는 믿을 수 있는 서버라고 등록을 해놨다면 edward_taker.com이 edward_giver 서버로 요청을 보내도 정상응답을 받을 수 있는 것이고 edward_taker 서버가 edward_giver 서버를 등록하지 않았다면 그 요청은 불발되고 브라우저가 에러를 띄우는 건가?

정확하게 이해하셨습니다. 다만, 주체와 방향을 조금 더 명확히 정리하면 완벽합니다. CORS 설정은 자원을 가진 서버(Giver)가 누구에게 허용할지(Taker)를 결정하는 보안 정책입니다.

말씀하신 예시를 바탕으로 구조를 다시 정리해 드릴게요.

1. 누가 누구를 등록해야 하나요?

CORS는 '데이터를 주는 서버'가 설정하는 것입니다.

  • 상황: edward_taker.com(클라이언트/프론트엔드)이 edward_giver.com(API 서버)에 데이터를 요청합니다.
  • 설정 주체: edward_giver 서버가 설정을 가지고 있어야 합니다.
  • 내용: edward_giver 서버 설정 파일에 "우리 데이터를 edward_taker.com 출처에서 가져가는 것을 허용한다"라는 화이트리스트를 등록하는 방식입니다.

2. 요청이 불발되는 시나리오

질문하신 내용처럼 등록 여부에 따라 결과가 달라집니다.

구분edward_giver 서버의 상태결과
허용 등록 시Access-Control-Allow-Origin: edward_taker.com 헤더를 응답에 포함브라우저가 응답을 확인하고 edward_taker의 스크립트에 데이터를 전달함 (성공)
미등록 시해당 헤더가 없거나 다른 도메인만 허용됨브라우저가 응답을 가로채서 에러를 발생시킴 (실패)

3. 브라우저가 에러를 띄우는 타이밍

여기서 재미있는 점은 "요청 자체는 서버에 도달할 수도 있다"는 것입니다.

  1. 단순 요청의 경우: 브라우저가 일단 edward_giver에게 데이터를 달라고 요청합니다. 서버는 평소처럼 데이터를 보내주지만, 응답 헤더에 "허용" 표시가 없으면 브라우저가 그 데이터를 파기하고 콘솔에 빨간색 CORS 에러를 띄웁니다.
  2. 예비 요청(Preflight)의 경우: 브라우저가 본 요청을 보내기 전에 "얘한테 데이터 줘도 돼?"라고 먼저 물어봅니다(OPTIONS 메서드). 이때 서버가 "안 돼"라고 하면 본 요청은 시작조차 하지 않습니다.

4. 왜 '받는 쪽(Taker)'은 설정이 필요 없나요?

CORS 에러는 '내 소중한 데이터를 아무나 가져가지 못하게 보호'하려는 서버의 방어 기제이기 때문입니다.

  • edward_taker 서버는 그저 요청을 보내는 입장일 뿐입니다.
  • 만약 edward_taker가 보낸 요청이 실패한다면, 그것은 edward_taker가 잘못해서가 아니라 edward_giver가 문을 열어주지 않았기 때문입니다.

요약

  • Giver(서버): "나는 edward_taker.com만 믿어. 얘네한테는 데이터 보내줄게." (설정 필요)
  • Taker(클라이언트): "나 edward_taker인데 데이터 좀 줘!" (설정 불필요, 요청만 보냄)
  • 브라우저(경찰): "Giver가 너(Taker) 허용 안 했네? 이 데이터는 못 보여줘!" (에러 발생)
profile
there ain't no shortcuts

0개의 댓글