CORS(Cross-Origin Resource Sharing)

μ›Ή μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ€ λ³΄μ•ˆμ„ μœ„ν•΄ 기본적으둜 동일 좜처 μ •μ±…(SOP)을 λ”°λ₯΄μ§€λ§Œ, λ‹€λ₯Έ 좜처의 λ¦¬μ†ŒμŠ€λ₯Ό μ‚¬μš©ν•΄μ•Ό ν•˜λŠ” μ •λ‹Ήν•œ 상황(API 호좜 λ“±)을 μœ„ν•΄ κ³ μ•ˆλœ μ˜ˆμ™Έ μ‘°ν•­μ΄μž λ³΄μ•ˆ λ©”μ»€λ‹ˆμ¦˜μ΄λ‹€.

Same-Origin Policy(동일 좜처 μ •μ±…)

λΈŒλΌμš°μ €λŠ” λ³΄μ•ˆμƒμ˜ 이유둜 μŠ€ν¬λ¦½νŠΈμ—μ„œ μ‹œμž‘λœ ꡐ차 좜처 HTTP μš”μ²­μ„ μ œν•œν•˜λŠ” Same-Origin Policy(SOP) 정책을 λ”°λ₯Έλ‹€.

좜처(Origin)의 μ •μ˜

μΆœμ²˜λŠ” μ•„λž˜μ˜ μš”μ†Œλ“€λ‘œ κ΅¬μ„±λ˜λ©°, 이 쀑 ν•˜λ‚˜λΌλ„ λ‹€λ₯΄λ©΄ λ‹€λ₯Έ 좜처(Cross-Origin)둜 κ°„μ£Όλœλ‹€.

  • λ‹€λ₯Έ 도메인 (example.com - test.com)

  • λ‹€λ₯Έ ν•˜μœ„ 도메인 (example.com - store.example.com)

  • λ‹€λ₯Έ 포트 (example.com:80 - example.com:90)

  • λ‹€λ₯Έ ν”„λ‘œν† μ½œ (https://example.com - http://example.com)

μ—¬κΈ°μ„œ https://example.comκ³Ό https://www.example.com도 λ‹€λ₯Έ λ„λ©”μΈμœΌλ‘œ κ°„μ£Όλ˜κΈ° λ•Œλ¬Έμ— μ£Όμ˜ν•΄μ•Όν•œλ‹€.

μ˜ˆμ‹œ(κΈ°μ€€ http://store.ogufamily.com)

URL
Result
Reason

http://store.ogufamily.com/babyogu.html

same origin

path만 λ‹€λ₯Έκ²½μš°

http://store.ogufamily.com/ogu.html

same origin

path만 λ‹€λ₯Έκ²½μš°

https://store.ogufamily.com

cross origin

ν”„λ‘œν† μ½œμ΄ λ‹€λ₯Έ 경우

http://store.ogufamily.com:81

cross origin

ν¬νŠΈκ°€ λ‹€λ₯Έκ²½μš°

http://news.ogufamily.com

cross origin

도메인이 λ‹€λ₯Έκ²½μš°

CORS λ™μž‘ μ‹œλ‚˜λ¦¬μ˜€

CORS μš”μ²­μ€ λΈŒλΌμš°μ €κ°€ μžλ™μœΌλ‘œ μ²˜λ¦¬ν•˜λ©°, μš”μ²­μ˜ 성격에 따라 크게 μ„Έ κ°€μ§€ μ‹œλ‚˜λ¦¬μ˜€λ‘œ λ‚˜λ‰œλ‹€.

1. Simple Request (λ‹¨μˆœ μš”μ²­)

μ˜ˆλΉ„ μš”μ²­(Preflight) 없이 λ°”λ‘œ λ³Έ μš”μ²­μ„ λ³΄λ‚΄λŠ” 방식이닀. μ•„λž˜ 쑰건을 λͺ¨λ‘ λ§Œμ‘±ν•΄μ•Ό ν•œλ‹€.

  • λ©”μ„œλ“œ: GET, HEAD, POST 쀑 ν•˜λ‚˜

  • 헀더: Accept, Accept-Language, Content-Language, Content-Type λ“± ν—ˆμš©λœ ν—€λ”λ§Œ μ‚¬μš©

  • Content-Type: application/x-www-form-urlencoded, multipart/form-data, text/plain 쀑 ν•˜λ‚˜

ν•˜μ§€λ§Œ μ΅œμ‹  μ›Ή APIλŠ” λŒ€λΆ€λΆ„ application/json을 μ‚¬μš©ν•˜λ―€λ‘œ λ‹¨μˆœ μš”μ²­ 쑰건을 λ§Œμ‘±ν•˜μ§€ λͺ»ν•΄ Preflightκ°€ λ°œμƒν•˜λŠ” κ²½μš°κ°€ λ§Žλ‹€.

2. Preflight Request(μ˜ˆλΉ„ μš”μ²­)

λ‹¨μˆœ μš”μ²­μ˜ 쑰건을 λ§Œμ‘±ν•˜μ§€ λͺ»ν•  경우(예: Content-Type: application/json λ˜λŠ” μ»€μŠ€ν…€ 헀더 μ‚¬μš©), λΈŒλΌμš°μ €λŠ” μ‹€μ œ μš”μ²­μ„ 보내기 전에 μ•ˆμ „ν•œμ§€ ν™•μΈν•˜κΈ° μœ„ν•΄ μ˜ˆλΉ„ μš”μ²­μ„ λ¨Όμ € 보낸닀.

spinner
  1. λΈŒλΌμš°μ €κ°€ OPTIONS λ©”μ„œλ“œλ‘œ μš”μ²­ 정보(Origin, Method, Header)λ₯Ό λ‹΄μ•„ μ„œλ²„μ— 전솑

  2. μ„œλ²„λŠ” ν—ˆμš© μ—¬λΆ€λ₯Ό 담은 헀더(Access-Control-Allow-*)와 ν•¨κ»˜ 응닡

  3. λΈŒλΌμš°μ €λŠ” μ„œλ²„ 응닡을 ν™•μΈν•˜κ³  μ•ˆμ „ν•˜λ‹€κ³  νŒλ‹¨λ˜λ©΄ μ‹€μ œ μš”μ²­μ„ 전솑

  4. λΈŒλΌμš°μ €λŠ” Preflight κ²°κ³Όλ₯Ό Access-Control-Max-Age μ‹œκ°„λ§ŒνΌ μΊμ‹±ν•˜μ—¬ 맀번 μ˜ˆλΉ„ μš”μ²­μ„ 보내지 μ•Šλ„λ‘ μ΅œμ ν™”

3. Credentialed Request (인증 정보λ₯Ό ν¬ν•¨ν•œ μš”μ²­)

ν΄λΌμ΄μ–ΈνŠΈκ°€ μΏ ν‚€λ‚˜ 인증 헀더(Authorization)λ₯Ό ν¬ν•¨ν•˜μ—¬ μš”μ²­μ„ 보낼 λ•Œ λ°œμƒν•œλ‹€.

  • ν΄λΌμ΄μ–ΈνŠΈ μ„€μ •: credentials: 'include' (fetch API) λ˜λŠ” withCredentials = true (axios/XHR) μ„€μ • ν•„μš”

  • μ„œλ²„ μ„€μ • μ œμ•½ 사항

    • Access-Control-Allow-Originμ—λŠ” μ™€μΌλ“œμΉ΄λ“œ(-)λ₯Ό μ‚¬μš©ν•  수 μ—†μœΌλ©°, λ°˜λ“œμ‹œ ꡬ체적인 Origin(예: http://localhost:3000) λͺ…μ‹œ ν•„μš”

    • Access-Control-Allow-Credentials: true 헀더 μΆ”κ°€ ν•„μš”

μ£Όμš” 응닡 헀더

μ„œλ²„λŠ” λ‹€μŒ 헀더듀을 톡해 CORS 정책을 λΈŒλΌμš°μ €μ— μ•Œλ¦°λ‹€.

  • Access-Control-Allow-Origin: μš”μ²­μ„ ν—ˆμš©ν•  좜처. 단일 도메인 λ˜λŠ” -

  • Access-Control-Allow-Methods: ν—ˆμš©ν•  HTTP λ©”μ„œλ“œ (GET, POST, PUT, OPTIONS λ“±)

  • Access-Control-Allow-Headers: ν—ˆμš©ν•  μ»€μŠ€ν…€ 헀더

  • Access-Control-Allow-Credentials: μΏ ν‚€ λ“± 인증 정보 ν—ˆμš© μ—¬λΆ€

  • Access-Control-Max-Age: Preflight μš”μ²­μ˜ μΊμ‹œ μ‹œκ°„(초)

참고자료

Last updated