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-Age | Preflight 캐시 시간 |
주의: Credentials + 와일드카드
동시에 쓸 수 없다:
Allow-Origin: *
Allow-Credentials: true
특정 출처를 명시해야 한다:
Allow-Origin: https://app.com
Allow-Credentials: true
실무 해결 패턴
| 상황 | 해결 |
|---|---|
| 개발 중 CORS 에러 | 프록시 설정 (Next.js rewrites) |
| API 서버 | 미들웨어로 CORS 헤더 추가 |
| 특정 도메인만 | 화이트리스트 방식 |
| 쿠키 기반 인증 | credentials + 특정 origin |
| CDN 리소스 | crossorigin 속성 추가 |