쿠키·세션·토큰과 CORS 기초: 로그인 정보와 출처 구분하기

··설명 약 11분·작성: 해비·블로그 소개

쿠키·세션·토큰과 CORS는 로그인 요청에서 각각 어떤 역할을 하나요?

쿠키는 브라우저가 저장해 조건에 따라 보내는 데이터이고, 세션과 토큰은 사용자 상태·인증을 다루는 개념입니다. CORS는 다른 출처의 응답을 브라우저에서 읽는 경계로 인증과 역할이 다릅니다.

적용 조건·범위: Credential이 포함되는 CORS 응답에서는 Access-Control-Allow-Origin에 무조건 와일드카드 별표를 사용하는 방식으로 처리할 수 없습니다. 구체적인 허용 origin과 Access-Control-Allow-Credentials 설정이 필요합니다.

공식 문서 참고: MDN: 쿠키·세션 식별자와 보안 속성 · MDN: CORS 사전 요청과 자격 증명 요청 조건

Cookie·Session·Token 먼저 구분하기

세 용어를 같은 종류의 로그인 방법처럼 외우면 이후 개념이 꼬이기 쉽습니다.

간단히 역할부터 나눠보겠습니다.

Cookie
→ 브라우저가 저장하고 조건에 따라 HTTP 요청에 보낼 수 있는 데이터

Session
→ 서버가 사용자별 상태를 관리하는 방식

Token
→ 인증이나 권한을 나타내는 값을 전달하는 방식

Session을 사용할 때 Session ID를 Cookie에 저장하는 구성이 흔합니다.

따라서 Cookie와 Session은 서로 경쟁하는 개념이 아닙니다.

브라우저 Cookie
sessionId=abc123
↓
요청 전송
↓
서버
abc123에 해당하는 Session 조회
↓
사용자 확인

반대로 Token 방식에서는 Authorization Header를 사용하는 경우가 많습니다.

Authorization: Bearer <token>

어떤 방식이든 서버는 요청에 포함된 정보를 바탕으로 사용자를 확인하고 권한을 판단합니다.

Cookie 기반 로그인 흐름

사용자가 로그인한다고 가정하겠습니다.

1. 로그인 요청
2. 서버가 인증 성공
3. 서버가 Session 생성
4. Session ID를 Cookie로 전달
5. 브라우저가 Cookie 저장
6. 이후 조건이 맞는 요청에 Cookie 포함
7. 서버가 Session 확인

Network에서 Cookie 관련 정보는 Request Headers 또는 Application의 Cookies 영역에서 확인할 수 있습니다.

서버가 Cookie를 내려줄 때는 Set-Cookie Header를 사용할 수 있습니다.

Set-Cookie: sessionId=abc123; Path=/; HttpOnly; Secure

실제 속성은 서비스 요구사항에 따라 달라집니다.

HttpOnly Cookie는 JavaScript에서 직접 읽지 못하도록 제한하는 데 도움이 됩니다.

Secure는 HTTPS 연결에서만 Cookie를 전송하도록 요구하는 속성입니다.

SameSite는 교차 사이트 상황에서 Cookie 전송 범위를 제어하는 데 사용됩니다.

각 속성이 모든 보안 문제를 해결하는 것은 아닙니다.

Token 기반 인증 흐름

Token을 직접 Authorization Header에 넣는 구조를 예로 보겠습니다.

fetch('/api/tasks', {
  headers: {
    Authorization: 'Bearer token-value'
  }
});

이 경우 브라우저가 Cookie처럼 자동으로 Authorization 값을 만들어 주는 것은 아닙니다.

애플리케이션 코드나 사용하는 인증 라이브러리가 Token을 관리하고 Header에 넣을 수 있습니다.

Token을 어디에 저장해야 하는지는 서비스 구조와 위협 모델에 따라 달라집니다.

localStorage가 항상 정답이거나 Cookie가 항상 정답이라고 단정하면 안 됩니다.

특히 XSS가 발생하면 JavaScript가 접근 가능한 저장소의 값이 노출될 수 있습니다.

4회차에서 이 부분을 보안 관점에서 다시 연결합니다.

origin은 무엇인가

origin은 기본적으로 다음 세 요소 조합으로 판단합니다.

scheme
host
port

예를 들어 다음 두 주소를 비교해보겠습니다.

https://example.com:443
https://api.example.com:443

host가 다르므로 서로 다른 origin입니다.

다음도 다릅니다.

http://example.com
https://example.com

scheme이 다릅니다.

개발 환경에서는 포트 차이도 중요합니다.

http://localhost:5173
http://localhost:3000

port가 다르므로 서로 다른 origin입니다.

Same-Origin Policy

브라우저는 웹페이지의 JavaScript가 다른 origin의 데이터에 자유롭게 접근하지 못하도록 제한합니다.

이 정책을 Same-Origin Policy라고 부릅니다.

중요한 점은 네트워크 요청 자체와 JavaScript가 응답을 읽는 권한을 구분하는 것입니다.

일부 교차 출처 요청은 서버까지 전송될 수 있지만 브라우저가 응답을 애플리케이션 JavaScript에 노출하지 않을 수 있습니다.

그래서 Network에는 요청 흔적이 있는데 fetch에서는 CORS 오류가 발생하는 상황을 볼 수 있습니다.

CORS가 필요한 이유

CORS는 Cross-Origin Resource Sharing의 약자입니다.

다른 origin의 웹페이지가 서버 응답을 읽을 수 있도록 서버가 허용 범위를 Header로 알려주는 방식입니다.

대표적인 응답 Header는 다음과 같습니다.

Access-Control-Allow-Origin
Access-Control-Allow-Methods
Access-Control-Allow-Headers
Access-Control-Allow-Credentials

예를 들어 서버가 특정 origin만 허용할 수 있습니다.

Access-Control-Allow-Origin: https://app.example.com

CORS 설정은 프론트엔드에서 마음대로 해제하는 기능이 아닙니다.

실제 API 서버가 허용 정책을 응답해야 합니다.

개발 중 브라우저 보안을 끄거나 확장 프로그램으로 CORS를 우회하면 원인을 해결한 것이 아닙니다.

preflight 요청

모든 교차 출처 요청이 바로 본 요청으로 진행되는 것은 아닙니다.

특정 조건에서는 브라우저가 먼저 OPTIONS 요청을 보내 서버가 해당 요청을 허용하는지 확인합니다.

이를 preflight라고 합니다.

브라우저
→ OPTIONS preflight
→ 서버 허용 응답
→ 실제 POST/PATCH/DELETE 등 요청

Network에서 OPTIONS 요청이 보인다면 실제 API 요청 앞의 확인 단계일 수 있습니다.

서버가 OPTIONS 요청을 올바르게 처리하지 못하면 실제 요청이 시작되지 않을 수 있습니다.

credentials가 필요한 요청

Cookie를 교차 출처 요청에 포함해야 한다면 fetch에서 credentials 설정이 필요할 수 있습니다.

fetch('https://api.example.com/tasks', {
  credentials: 'include'
});

서버도 이에 맞는 CORS 설정을 제공해야 합니다.

Credential이 포함되는 CORS 응답에서는 Access-Control-Allow-Origin에 무조건 와일드카드 별표를 사용하는 방식으로 처리할 수 없습니다. 구체적인 허용 origin과 Access-Control-Allow-Credentials 설정이 필요합니다.

또한 Cookie 자체의 Domain·Path·Secure·SameSite 조건도 모두 영향을 줄 수 있습니다.

따라서 Cookie가 안 간다고 해서 무조건 CORS 하나만 수정하면 되는 것이 아닙니다.

401·403·CORS 구분

세 문제를 자주 혼동합니다.

401

서버가 요청을 받았지만 인증 정보가 없거나 유효하지 않다고 판단하는 경우 대표적으로 사용됩니다.

요청 서버 도착
→ 인증 실패
→ 401 응답

403

사용자 식별은 되었더라도 해당 작업 권한이 없을 때 대표적으로 사용됩니다.

요청 서버 도착
→ 권한 부족
→ 403 응답

서비스 구현에 따라 401과 403 사용 방식은 달라질 수 있으므로 실제 API 규약을 함께 확인해야 합니다.

CORS 오류

브라우저가 교차 출처 응답을 JavaScript에 노출할 수 없다고 판단한 상황입니다.

요청 또는 preflight
→ 서버 응답
→ 브라우저 CORS 검사
→ JavaScript 접근 차단

CORS는 서버의 인증 결과와 다른 레이어의 문제입니다.

자주 하는 오해

Session은 Cookie입니다

아닙니다.

Session은 서버 상태 관리 방식이고 Cookie는 브라우저 저장·전송 메커니즘입니다.

Session ID를 Cookie에 넣어 함께 사용하는 구성이 흔할 뿐입니다.

Token은 무조건 localStorage에 저장합니다

아닙니다.

저장 위치는 보안 요구사항과 인증 구조를 보고 결정해야 합니다.

CORS는 서버 보안 기능 전체를 의미합니다

아닙니다.

CORS는 브라우저에서 교차 출처 응답 접근을 제어하는 메커니즘입니다.

서버의 인증·권한 검증 자체를 대신하지 않습니다.

CORS 오류는 프론트엔드 Header를 추가하면 해결됩니다

항상 그렇지 않습니다.

서버가 적절한 Access-Control-Allow-* 응답 Header를 제공해야 하는 경우가 많습니다.

SameSite와 CORS는 같은 기능입니다

아닙니다.

SameSite는 Cookie 전송 정책과 관련되고 CORS는 교차 출처 응답 접근 정책과 관련됩니다.

독자 질문과 실전 확인

독자 질문

로그인은 성공했는데 다음 API 요청이 401이거나 CORS 오류로 막히면 무엇부터 구분해야 할까요?

웹 개발 사례

TaskFlow의 로그인 응답이 Set-Cookie를 보냈더라도 다음 교차 출처 fetch에 Cookie가 실리지 않으면 인증이 실패할 수 있습니다. 반면 CORS는 브라우저가 응답을 읽도록 허용할지 판단하는 출처 정책입니다.

직접 확인할 문제

Network에서 로그인 응답의 Set-Cookie, 다음 요청의 Cookie·Origin, OPTIONS 요청 여부, 실제 API Status를 순서대로 적으세요. OPTIONS가 실패해 실제 요청이 나가지 않은 경우와 API가 401을 반환한 경우를 구분해 보세요.

예상 결과와 판단

OPTIONS 단계에서 막혔다면 서버의 허용 출처·메서드·헤더와 credentials 조건을 검토합니다. 실제 API가 401을 반환했다면 요청에 인증 정보가 포함됐는지와 세션·토큰의 유효성을 확인합니다. 401만으로 쿠키 누락을 단정하지 않습니다.

검증 범위

가상 로그인 흐름입니다. 실제 인증 서버 설정, 쿠키 속성, 브라우저별 제3자 쿠키 정책은 실행 검증하지 않았습니다. 토큰 저장 위치도 서비스 설계에 따라 다릅니다.

다음 학습: 4회차에서는 인증 상태를 악용하는 CSRF와 신뢰할 수 없는 스크립트 실행인 XSS를 나눕니다.

학습 완료 체크리스트

  • Cookie·Session·Token의 역할을 구분할 수 있습니다.
  • Session ID가 Cookie에 저장될 수 있는 이유를 설명할 수 있습니다.
  • origin의 scheme·host·port를 구분할 수 있습니다.
  • Same-Origin Policy와 CORS의 관계를 설명할 수 있습니다.
  • OPTIONS preflight 요청을 Network에서 식별할 수 있습니다.
  • 401·403·CORS 오류를 같은 문제로 보지 않습니다.
  • credentials와 Cookie 속성을 함께 확인해야 한다는 것을 이해했습니다.

선택 실습: 같은 프로젝트로 연습하기

이 선택 실습은 TaskFlow의 요청 흐름을 설명하는 분석 노트를 만드는 연습입니다. 실행 앱을 새로 만드는 과정은 아닙니다.

요청에 인증 정보가 어떻게 포함되는지와 브라우저가 출처를 어떻게 판단하는지 추가합니다.

TaskFlow 요청 흐름 분석 노트

이전 체크포인트

cs-step-02-network-path

현재 상태

지금까지 분석 노트는 연결과 HTTP 요청까지만 추적합니다.

URL
→ DNS
→ TCP/TLS
→ HTTP 요청
→ HTTP 응답

이번 목표

요청에 인증 정보가 어떻게 포함되는지와 브라우저가 출처를 어떻게 판단하는지 추가합니다.

HTTP 요청
├─ Cookie
├─ Authorization
└─ Origin
↓
서버 인증·권한 판단
↓
CORS 응답 Header
↓
브라우저가 응답 접근 허용 여부 판단

TaskFlow 관찰 시나리오

로그인된 API 요청 하나를 기준으로 다음을 확인합니다.

Request Headers
- Cookie 존재 여부
- Authorization 존재 여부
- Origin 존재 여부

Response
- Status Code
- Access-Control-Allow-Origin
- Access-Control-Allow-Credentials

실제 서비스 구조에 따라 일부 항목은 없을 수 있습니다.

Before

API 실패
→ 로그인 문제인지
→ 권한 문제인지
→ CORS 문제인지
구분하기 어려움

After

401
→ 인증 정보 확인

403
→ 권한 확인

CORS 오류
→ origin·preflight·응답 CORS Header 확인

Cookie 미전송
→ credentials·Cookie 속성 함께 확인

현재 확장 단계

✓ 1. 브라우저·HTTP 요청/응답
✓ 2. DNS·TCP·TLS
→ 3. 쿠키·세션·토큰·CORS
○ 4. CSRF·XSS
○ 5. HTTP 캐시
○ 6. 프로세스·스레드·메모리
○ 7. 통합 장애 진단

완료 체크포인트

cs-step-03-auth-cors

다음 학습

인증 정보와 출처 정책을 이해하면 웹 보안 공격의 차이도 더 명확해집니다.

다음 글에서는 사용자의 인증 상태를 악용하는 CSRF와 신뢰하지 않은 입력이 스크립트 실행으로 이어지는 XSS를 비교합니다.

다음 글: CSRF XSS 차이: 프론트엔드 보안 공격 구분법

글 소개·학습 준비·전체 목차
쿠키·세션·토큰과 인증 경계를 표현한 쿠키·열쇠·출입문

CS 기초 · 3 / 7 · 필수 학습 · 인증과 CORS

서버에 정상적으로 연결했다고 해서 모든 요청을 브라우저가 같은 방식으로 처리하는 것은 아닙니다.

로그인 상태를 유지하려면 인증 정보가 필요하고, 다른 출처의 서버에서 데이터를 읽으려면 브라우저의 출처 정책도 이해해야 합니다.

이번 글에서는 Cookie·Session·Token과 Same-Origin Policy·CORS를 하나의 요청 흐름에서 연결하되 서로 다른 역할로 구분합니다.

이번 글에서 배우는 내용

  • Cookie가 저장되고 요청에 포함되는 기본 원리
  • Session이 서버 상태와 연결되는 방식
  • Token이 인증 정보로 사용되는 방식
  • Cookie 기반 Session과 Bearer Token 차이
  • origin을 구성하는 scheme·host·port
  • Same-Origin Policy와 CORS의 역할
  • preflight OPTIONS 요청
  • 401·403·CORS 오류의 차이

선수 지식

  • HTTP 요청과 응답
  • Request Headers와 Response Headers
  • URL의 scheme·host·port
  • DNS·연결·HTTP 오류의 기본 차이

목차

  1. Cookie·Session·Token 먼저 구분하기
  2. Cookie 기반 로그인 흐름
  3. Token 기반 인증 흐름
  4. origin은 무엇인가
  5. Same-Origin Policy
  6. CORS가 필요한 이유
  7. preflight 요청
  8. credentials가 필요한 요청
  9. 401·403·CORS 구분
  10. 자주 하는 오해
  11. 독자 질문과 실전 확인
  12. 학습 완료 체크리스트
  13. TaskFlow 요청 흐름 분석 노트
  14. 현재 확장 단계
  15. 다음 학습

이 글이 도움이 되었나요?

조회 중

읽음 기록

읽음 — / 전체 7개 · 필수 7개

이 글을 쓴 해비

웹사이트를 제작·운영하고, 개인 서비스와 자동화·AI 도구를 만듭니다. 직접 만들며 배운 내용과 문제 해결 과정을 BlogFlow에 기록합니다.

새 글 받아보기

RSS 리더에서 BlogFlow의 새 글을 확인할 수 있습니다.

RSS 피드 구독하기

댓글 남기기