๊ด‘๊ณ  ์ฐจ๋‹จ ํ”„๋กœ๊ทธ๋žจ์ด ๊ฐ์ง€๋˜์—ˆ์Šต๋‹ˆ๋‹ค

์ด ์‚ฌ์ดํŠธ๋Š” ๊ด‘๊ณ  ์ˆ˜์ต์„ ํ†ตํ•ด ๋ฌด๋ฃŒ๋กœ ์ฝ˜ํ…์ธ ์™€ ์„œ๋น„์Šค๋ฅผ ์ œ๊ณตํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

๋” ๋‚˜์€ ์„œ๋น„์Šค๋ฅผ ์œ„ํ•ด ๊ด‘๊ณ  ์ฐจ๋‹จ ํ”„๋กœ๊ทธ๋žจ์„ ๋น„ํ™œ์„ฑํ™” ํ•ด์ฃผ์„ธ์š”.

๊ด‘๊ณ  ์ฐจ๋‹จ ํ•ด์ œ ๋ฐฉ๋ฒ• ๋ณด๊ธฐ
Loading...

Nginx CORS(Cross-Origin Resource Sharing) ์ •์ฑ…

Nginx CORS(Cross-Origin Resource Sharing) ์ •์ฑ…์— ๋Œ€ํ•œ img

๐Ÿ“ ์„œ๋ก 

  • [์ฃผ์ œ ์†Œ๊ฐœ]: ์˜ค๋Š˜ ๋‹ค๋ฃฐ ์ฃผ์ œ๋Š” ๋ฐ”๋กœ ์›น ๊ฐœ๋ฐœ๊ณผ ์šด์˜์˜ ํ•„์ˆ˜ ์š”์†Œ์ธย Nginx CORS(Cross-Origin Resource Sharing) ์ •์ฑ…์ž…๋‹ˆ๋‹ค. ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•˜๊ณ  ๋ฐฐํฌํ•˜๋Š” ๊ณผ์ •์—์„œ "CORS ์˜ค๋ฅ˜"๋ผ๋Š” ๋นจ๊ฐ„ ๊ธ€์”จ๋ฅผ ํ•œ ๋ฒˆ์ฏค์€ ๋งˆ์ฃผ์น˜์…จ์„ ํ…๋ฐ์š”. ์ด CORS๊ฐ€ ๋ฌด์—‡์ธ์ง€, Nginx์—์„œ ์–ด๋–ป๊ฒŒ ์„ค์ •ํ•˜๊ณ , ์™œ ์ œ๋Œ€๋กœ ๊ด€๋ฆฌํ•ด์•ผ ํ•˜๋Š”์ง€ ๊ทธ ์ค‘์š”์„ฑ์„ ๊นŠ์ด ํŒŒํ—ค์ณ ๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. ๋‹จ์ˆœํžˆ ์˜ค๋ฅ˜๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ฒƒ์„ ๋„˜์–ด, ๋ณด์•ˆ๊ณผ ์•ˆ์ •์„ฑ์„ ๋™์‹œ์— ์žก๋Š” ์‹ค์ „ ๋…ธํ•˜์šฐ๋ฅผ ๊ณต์œ ํ•ด ๋“œ๋ฆด ๊ฒƒ์ž…๋‹ˆ๋‹ค.
  • [์™œ ์ž‘์„ฑํ•˜์˜€๋Š”๊ฐ€? ]: ์ด ๊ธ€์€ ๋‹จ์ˆœํžˆ CORS ์—๋Ÿฌ๋ฅผ ์—†์• ๋Š” ์ž„์‹œ๋ฐฉํŽธ์ด ์•„๋‹Œ, ๊ทผ๋ณธ์ ์ธ ์ดํ•ด์™€ ์‹ค๋ฌด์—์„œ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋Š” ์ž ์žฌ์  ์œ„ํ—˜์„ ํšŒํ”ผํ•˜๊ณ  ๋” ๋‚˜์•„๊ฐ€ ์‹œ์Šคํ…œ์˜ ๋ณด์•ˆ ์ˆ˜์ค€์„ ํ•œ ๋‹จ๊ณ„ ๋Œ์–ด์˜ฌ๋ฆด ์ˆ˜ ์žˆ๋Š” ํ†ต์ฐฐ๋ ฅ์„ ์ œ๊ณตํ•˜๊ณ ์ž ์ž‘์„ฑ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋…์ž ์—ฌ๋Ÿฌ๋ถ„์€ ์ด ๊ธ€์„ ํ†ตํ•ด Nginx CORS ์ •์ฑ…์„ ์™„๋ฒฝํ•˜๊ฒŒ ๋งˆ์Šคํ„ฐํ•˜๊ณ , ๋ณต์žกํ•œ ์›น ํ™˜๊ฒฝ์—์„œ๋„ ์œ ์—ฐํ•˜๊ณ  ์•ˆ์ „ํ•˜๊ฒŒ ์„œ๋น„์Šค๋ฅผ ์šด์˜ํ•˜๋Š” ๋ฐ ํ•„์š”ํ•œ ์ง€์‹๊ณผ ์‹ค์ „ ํŒ์„ ์–ป์–ด๊ฐ€์‹ค ์ˆ˜ ์žˆ์„ ๊ฒƒ์ž…๋‹ˆ๋‹ค.


๐ŸŒ Nginx CORS ์ •์ฑ…: ํ•ต์‹ฌ ๊ฐœ๋… ํŒŒํ—ค์น˜๊ธฐ

  • [CORS (Cross-Origin Resource Sharing)]: ๐Ÿš€ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋‹ค๋ฅธย Origin(์ถœ์ฒ˜)์˜ ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ํ—ˆ์šฉํ•˜๋Š” ๋ฉ”์ปค๋‹ˆ์ฆ˜์ž…๋‹ˆ๋‹ค. Origin์€ ํ”„๋กœํ† ์ฝœ(http/https), ๋„๋ฉ”์ธ(www.example.com), ํฌํŠธ(80/443/8080)์˜ ์กฐํ•ฉ์œผ๋กœ ๊ฒฐ์ •๋ฉ๋‹ˆ๋‹ค. ์ด ์ค‘ ํ•˜๋‚˜๋ผ๋„ ๋‹ค๋ฅด๋ฉด "๋‹ค๋ฅธ Origin"์œผ๋กœ ๊ฐ„์ฃผ๋ฉ๋‹ˆ๋‹ค.
  • ์™œ ์ค‘์š”ํ•œ๊ฐ€์š”?: ํ˜„๋Œ€ ์›น์€ ์ˆ˜๋งŽ์€ ์„œ๋น„์Šค์™€ API๊ฐ€ ์„œ๋กœ ์—ฐ๋™๋˜๋Š” ๋ณต์žกํ•œ ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด,ย frontend.com์˜ ์›น ํŽ˜์ด์ง€์—์„œย api.backend.com์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜, ๋‹ค๋ฅธ CDN์—์„œ ์ด๋ฏธ์ง€๋ฅผ ๋กœ๋“œํ•˜๋Š” ๊ฒฝ์šฐ ๋“ฑ ๋‹ค๋ฅธ Origin ๊ฐ„์˜ ํ†ต์‹ ์ด ๋นˆ๋ฒˆํ•˜๊ฒŒ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. CORS๋Š” ์ด๋Ÿฌํ•œ ๊ต์ฐจ Origin ํ†ต์‹ ์„ ์•ˆ์ „ํ•˜๊ฒŒ ํ—ˆ์šฉํ•˜๊ธฐ ์œ„ํ•œ ํ‘œ์ค€ํ™”๋œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.
  • [๋™์ผ ์ถœ์ฒ˜ ์ •์ฑ… (Same-Origin Policy - SOP)]: ๐Ÿ›ก๏ธ ์›น ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํŠน์ • Origin์—์„œ ๋กœ๋“œ๋œ ๋ฌธ์„œ๋‚˜ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋‹ค๋ฅธ Origin์˜ ๋ฆฌ์†Œ์Šค์™€ ์ƒํ˜ธ ์ž‘์šฉํ•˜๋Š” ๊ฒƒ์„ ์ œํ•œํ•˜๋Š” ๊ทผ๋ณธ์ ์ธ ๋ณด์•ˆ ์›์น™์ž…๋‹ˆ๋‹ค.ย evil.com์ดย yourbank.com์˜ ๋ฏผ๊ฐํ•œ ์ •๋ณด๋ฅผ ๋ชฐ๋ž˜ ์ฝ์–ด๊ฐ€๋Š” ๊ฒƒ์„ ๋ง‰๋Š” ๋ฐฉํŒจ์™€ ๊ฐ™์Šต๋‹ˆ๋‹ค.
  • ๋†“์น˜๊ธฐ ์‰ฌ์šด ์ : ๋งŽ์€ ๊ฐœ๋ฐœ์ž๊ฐ€ CORS ์˜ค๋ฅ˜๋ฅผ ๋งŒ๋‚˜๋ฉด ๋‹จ์ˆœํžˆ "๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋ง‰๊ณ  ์žˆ๊ตฌ๋‚˜"๋ผ๊ณ ๋งŒ ์ƒ๊ฐํ•˜๊ณ  SOP์˜ ๊ทผ๋ณธ์ ์ธ ๋ณด์•ˆ ์ค‘์š”์„ฑ์„ ๊ฐ„๊ณผํ•˜๊ณค ํ•ฉ๋‹ˆ๋‹ค. SOP๋Š” ์‚ฌ์šฉ์ž ์ •๋ณด ๋ณดํ˜ธ์˜ ์ฒซ ๋ฒˆ์งธ ๋ฐฉ์–ด์„ ์ด๋ฉฐ, CORS๋Š” ์ด ๋ฐฉ์–ด์„ ์„ ํ•ฉ๋ฒ•์ ์œผ๋กœ ํ†ต๊ณผํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์ผํ•œ ํ†ต๋กœ์ž…๋‹ˆ๋‹ค.ย Access-Control-Allow-Origin: *์„ ๋ฌด์‹ฌ์ฝ” ์‚ฌ์šฉํ•˜๋ฉด ์ด ์ค‘์š”ํ•œ ๋ฐฉ์–ด์„ ์„ ๋ฌด๋ ฅํ™”์‹œํ‚ค๋Š” ๊ฒƒ๊ณผ ๊ฐ™์Šต๋‹ˆ๋‹ค.
  • [Access-Control-Allow-Origin ํ—ค๋”]: ๐Ÿ”‘ ์„œ๋ฒ„๊ฐ€ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ "์ด ๋ฆฌ์†Œ์Šค๋Š” ํŠน์ • Origin์—์„œ๋งŒ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์–ด" ๋˜๋Š” "์ด ๋ฆฌ์†Œ์Šค๋Š” ๋ชจ๋“  Origin์—์„œ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์–ด"๋ผ๊ณ  ์•Œ๋ ค์ฃผ๋Š” HTTP ์‘๋‹ต ํ—ค๋”์ž…๋‹ˆ๋‹ค.
  • ์‹ค๋ฌด ์ ์šฉ ์‹œ ๊ณ ๋ ค์‚ฌํ•ญ:
  • *ย (์™€์ผ๋“œ์นด๋“œ): ๋ชจ๋“  Origin์„ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค. ๋ณด์•ˆ์ƒ ๊ฐ€์žฅ ์ทจ์•ฝํ•˜๋ฉฐ, ๋ฏผ๊ฐํ•œ ์ •๋ณด๋ฅผ ๋‹ค๋ฃจ๋Š” API์—์„œ๋Š” ์ ˆ๋Œ€ ์‚ฌ์šฉํ•ด์„œ๋Š” ์•ˆ ๋ฉ๋‹ˆ๋‹ค.
  • https://www.example.com: ํŠน์ • ๋‹จ์ผ Origin๋งŒ ํ—ˆ์šฉํ•ฉ๋‹ˆ๋‹ค. ๊ฐ€์žฅ ์•ˆ์ „ํ•œ ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค.
  • https://sub.example.com, https://another.example.com: ์—ฌ๋Ÿฌ Origin์„ ํ—ˆ์šฉํ•ด์•ผ ํ•  ๊ฒฝ์šฐ, Nginx์—์„œ๋Š” ์—ฌ๋Ÿฌย add_headerย ์ง€์‹œ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ๊ฐœ๋ณ„์ ์œผ๋กœ ์„ค์ •ํ•˜๊ฑฐ๋‚˜,ย $http_originย ๋ณ€์ˆ˜๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋™์ ์œผ๋กœ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.


๐Ÿ“œ Nginx CORS ์ •์ฑ…: ๊ณต์‹ ๊ฐ€์ด๋“œ๋ผ์ธ & ๊ถŒ์žฅ ์‚ฌํ•ญ

  • [๊ณต์‹ ์†Œ์Šค]: Nginx ๊ณต์‹ ๋ฌธ์„œ (nginx.org/en/docs/http/ngx_http_headers_module.html#add_header) ๋ฐ Mozilla ๊ฐœ๋ฐœ์ž ๋„คํŠธ์›Œํฌ(MDN)์˜ CORS ๋ฌธ์„œ(developer.mozilla.org/ko/docs/Web/HTTP/CORS)๋ฅผ ์ฐธ๊ณ ํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ •ํ™•ํ•˜๊ณ  ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • [์ฃผ์š” ๊ถŒ์žฅ ์‚ฌํ•ญ]:
  • ์•ˆ์ „ ์ œ์ผ ์›์น™: ๐Ÿšจย Access-Control-Allow-Origin: *ย ์‚ฌ์šฉ์€ ๊ทน๋„๋กœ ์ž์ œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ํŠนํžˆ ๋กœ๊ทธ์ธ ์ •๋ณด, ๊ฐœ์ธ ๋ฐ์ดํ„ฐ, ๊ฒฐ์ œ ์ •๋ณด ๋“ฑ ๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฒ˜๋ฆฌํ•˜๋Š” API์—์„œ๋Š” ์ ˆ๋Œ€ ๊ธˆ์ง€์ž…๋‹ˆ๋‹ค. ํ—ˆ์šฉํ•ด์•ผ ํ•  Origin์„ ๋ช…ํ™•ํžˆ ์ง€์ •ํ•˜์—ฌ ์ตœ์†Œ ๊ถŒํ•œ์˜ ์›์น™์„ ์ง€ํ‚ค์„ธ์š”.
  • ํŠน์ • Origin ๋ช…์‹œ: ๐ŸŽฏ ๊ฐ€๋Šฅํ•œ ํ•œ ํŠน์ • Origin(์˜ˆ:ย https://your-frontend.com)๋งŒ ํ—ˆ์šฉํ•˜๋„๋ก ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ Origin์„ ํ—ˆ์šฉํ•ด์•ผ ํ•œ๋‹ค๋ฉด, ๊ฐ Origin์„ ๋ช…์‹œ์ ์œผ๋กœ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ย $http_originย ๋ณ€์ˆ˜๋ฅผ ํ™œ์šฉํ•œ ์กฐ๊ฑด๋ถ€ ์„ค์ •์„ ๊ณ ๋ คํ•˜์„ธ์š”.
  • OPTIONSย ๋ฉ”์„œ๋“œ ์ฒ˜๋ฆฌ: โš™๏ธ Preflight ์š”์ฒญ(์‚ฌ์ „ ์š”์ฒญ)์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ดย OPTIONSย HTTP ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•œ ์ ์ ˆํ•œ ์‘๋‹ต์„ ๊ตฌ์„ฑํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค. ์ด๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์‹ค์ œ ์š”์ฒญ์„ ๋ณด๋‚ด๊ธฐ ์ „์— ์„œ๋ฒ„๊ฐ€ CORS๋ฅผ ํ—ˆ์šฉํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ณผ์ •์ž…๋‹ˆ๋‹ค.
  • Access-Control-Allow-Credentialsย ์ฃผ์˜: ๐Ÿช ์ฟ ํ‚ค๋‚˜ HTTP ์ธ์ฆ๊ณผ ๊ฐ™์€ ์ž๊ฒฉ ์ฆ๋ช…์„ ํ—ˆ์šฉํ•˜๋Š”ย Access-Control-Allow-Credentials: trueย ํ—ค๋”๋Š”ย Access-Control-Allow-Origin: *์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝ์šฐ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์˜ค๋ฅ˜๋ฅผ ๋ฐœ์ƒ์‹œํ‚ต๋‹ˆ๋‹ค. ์ž๊ฒฉ ์ฆ๋ช…์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ ๋ฐ˜๋“œ์‹œ ํŠน์ • Origin์„ ๋ช…์‹œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • ์บ์‹ฑ ์ „๋žต ๊ณ ๋ ค: ๐Ÿ’จ CORS ํ—ค๋”๋„ ์บ์‹ฑ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.ย Vary: Originย ํ—ค๋”๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ Origin์— ๋”ฐ๋ผ ์บ์‹ฑ๋˜๋„๋ก ์„ค์ •ํ•˜๋ฉด, ๋‹ค๋ฅธ Origin์˜ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ž˜๋ชป๋œ ์บ์‹œ๋œ ์‘๋‹ต์„ ๋ฐ›์ง€ ์•Š๋„๋ก ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.


๐Ÿ› ๏ธ Nginx CORS ์ •์ฑ…: ์‹ค๋ฌด ์ ์šฉ ๋งˆ์Šคํ„ฐ ํ”Œ๋žœ

CORS ์ •์ฑ…์„ Nginx์— ์•ˆ์ „ํ•˜๊ฒŒ ์ ์šฉํ•˜๋Š” ๋‹จ๊ณ„๋ณ„ ๊ฐ€์ด๋“œ์ž…๋‹ˆ๋‹ค.

  1. [์ฒซ ๋ฒˆ์งธ ๋‹จ๊ณ„: ํ˜„์žฌ CORS ์š”๊ตฌ์‚ฌํ•ญ ๋ถ„์„]
  • ๋ฌด์—‡์„ ํ•˜๋Š”๊ฐ€?: ํ˜„์žฌ ์„œ๋น„์Šค ์ค‘์ธ ํ”„๋ก ํŠธ์—”๋“œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜(SPA, ๋ชจ๋ฐ”์ผ ์•ฑ ๋“ฑ)์ด ์–ด๋–ค ๋ฐฑ์—”๋“œ API๋ฅผ ํ˜ธ์ถœํ•˜๋ฉฐ, ๊ฐ API์— ๋Œ€ํ•ด ์–ด๋–ค Origin์—์„œ ์ ‘๊ทผํ•ด์•ผ ํ•˜๋Š”์ง€ ๋ช…ํ™•ํ•˜๊ฒŒ ํŒŒ์•…ํ•ฉ๋‹ˆ๋‹ค.
  • ์–ด๋–ป๊ฒŒ ํ•˜๋Š”๊ฐ€?:
  • ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœํŒ€๊ณผ ํ˜‘์˜ํ•˜์—ฌ ์„œ๋น„์Šค์— ํ•„์š”ํ•œ ์ •ํ™•ํ•œ Origin ๋ชฉ๋ก์„ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • ๊ฐ API ์—”๋“œํฌ์ธํŠธ๊ฐ€ ๋ฏผ๊ฐํ•œ ์ •๋ณด๋ฅผ ๋‹ค๋ฃจ๋Š”์ง€, ์ž๊ฒฉ ์ฆ๋ช…(์ฟ ํ‚ค, ํ† ํฐ ๋“ฑ)์„ ํ•„์š”๋กœ ํ•˜๋Š”์ง€ ์‹๋ณ„ํ•ฉ๋‹ˆ๋‹ค.
# ์˜ˆ์‹œ: ์š”๊ตฌ์‚ฌํ•ญ ์ •์˜ (๊ฐ€์ƒ์˜ ์‹œ๋‚˜๋ฆฌ์˜ค)
# Before
# ํ˜„์žฌ Nginx ์„ค์ •์€ Access-Control-Allow-Origin: * ์ด ์ „์—ญ์œผ๋กœ ์ ์šฉ๋˜์–ด ์žˆ๋‹ค.
# ์ด๋กœ ์ธํ•ด ๋ถˆํ•„์š”ํ•˜๊ฒŒ ๋ชจ๋“  Origin์—์„œ ์ ‘๊ทผ์ด ํ—ˆ์šฉ๋˜๊ณ  ์žˆ๋‹ค.

# After
# - ๋ฉ”์ธ ์„œ๋น„์Šค ํ”„๋ก ํŠธ์—”๋“œ: https://app.example.com
# - ๊ด€๋ฆฌ์ž ํŽ˜์ด์ง€ ํ”„๋ก ํŠธ์—”๋“œ: https://admin.example.com
# - ๋ชจ๋ฐ”์ผ ์•ฑ (์›น๋ทฐ): CORS๋Š” ์•„๋‹ˆ์ง€๋งŒ, ๋™์ผ Origin ์ •์ฑ…์„ ์œ„ํ•œ ๊ณ ๋ ค ํ•„์š” (์˜ˆ: ๋ธŒ๋ฆฟ์ง€)
# - API Gateway: https://api.example.com (๋ฐฑ์—”๋“œ ์„œ๋น„์Šค)
# - ์š”๊ตฌ์‚ฌํ•ญ: /api/v1/* ๊ฒฝ๋กœ์—๋Š” https://app.example.com ๊ณผ https://admin.example.com ๋งŒ ํ—ˆ์šฉํ•ด์•ผ ํ•˜๋ฉฐ, ์ž๊ฒฉ ์ฆ๋ช…(์ฟ ํ‚ค)์„ ํฌํ•จํ•ด์•ผ ํ•œ๋‹ค.
# ๋ฌด์—‡์ด ์–ด๋–ป๊ฒŒ ๋ณ€ํ–ˆ๋Š”์ง€ ์š”์•ฝ
# ๊ธฐ์กด์˜ ๊ด‘๋ฒ”์œ„ํ•œ CORS ํ—ˆ์šฉ ์ •์ฑ…์—์„œ ํ•„์š”ํ•œ Origin๋งŒ ๋ช…ํ™•ํžˆ ์ง€์ •ํ•˜์—ฌ ๋ณด์•ˆ์„ ๊ฐ•ํ™”ํ•˜๊ณ , ๊ฐ ์„œ๋น„์Šค์˜ ํŠน์„ฑ์— ๋งž๋Š” CORS ์„ค์ •์„ ์ค€๋น„ํ•œ๋‹ค.
  • ์„ฑ๊ณต ์ ๊ฒ€: ๋ชจ๋“  ํ”„๋ก ํŠธ์—”๋“œ ์„œ๋น„์Šค์˜ URL๊ณผ ํ•ด๋‹น ์„œ๋น„์Šค๊ฐ€ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฑ์—”๋“œ API์˜ URL ๋ชฉ๋ก, ๊ทธ๋ฆฌ๊ณ  ์ž๊ฒฉ ์ฆ๋ช… ์š”๊ตฌ ์—ฌ๋ถ€๊ฐ€ ๋ช…ํ™•ํžˆ ์ •์˜๋œ ๋ฌธ์„œ(์˜ˆ: Confluence, Notion)๊ฐ€ ์ค€๋น„๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • ์‹ค์ˆ˜ ๋ฐฉ์ง€ ํŒ: โš ๏ธ ๊ฐœ๋ฐœ์ž๋งˆ๋‹ค ๋‹ค๋ฅธ Origin์„ ์ด์•ผ๊ธฐํ•  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ์ตœ์ข…์ ์œผ๋กœ ์„œ๋น„์Šค์— ๋ฐฐํฌ๋  Origin์„ ๊ธฐ์ค€์œผ๋กœ ์‚ผ์•„์•ผ ํ•ฉ๋‹ˆ๋‹ค. ๋กœ์ปฌ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ(์˜ˆ:ย http://localhost:3000)์€ ์‹ค์ œ ์šด์˜ ํ™˜๊ฒฝ๊ณผ ๋‹ค๋ฅผ ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ, ์šด์˜ ํ™˜๊ฒฝ Origin์„ ์ตœ์šฐ์„ ์œผ๋กœ ๊ณ ๋ คํ•˜์„ธ์š”.
  1. [๋‘ ๋ฒˆ์งธ ๋‹จ๊ณ„: Nginx ์„ค์ • ํŒŒ์ผ ์ˆ˜์ • - ํŠน์ • Origin ํ—ˆ์šฉ]
  • ๋ฌด์—‡์„ ํ•˜๋Š”๊ฐ€?: ๋ถ„์„๋œ ์š”๊ตฌ์‚ฌํ•ญ์„ ๋ฐ”ํƒ•์œผ๋กœย nginx.confย ๋˜๋Š” ํ•ด๋‹น ์„œ๋น„์Šค์˜ย serverย ๋ธ”๋ก ์„ค์ • ํŒŒ์ผ์— CORS ํ—ค๋”๋ฅผ ์ถ”๊ฐ€ํ•ฉ๋‹ˆ๋‹ค.
  • ์–ด๋–ป๊ฒŒ ํ•˜๋Š”๊ฐ€?:ย locationย ๋ธ”๋ก ๋‚ด์—์„œย add_headerย ์ง€์‹œ๋ฌธ์„ ์‚ฌ์šฉํ•˜์—ฌ ํŠน์ • Origin์„ ํ—ˆ์šฉํ•˜๊ณ ย OPTIONSย ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•ฉ๋‹ˆ๋‹ค.
# ์˜ˆ์‹œ ์ฝ”๋“œ ๋˜๋Š” ๋ช…๋ น์–ด
# Before
# http {
#     add_header 'Access-Control-Allow-Origin' '*'; # ์ „์—ญ ์™€์ผ๋“œ์นด๋“œ CORS (์ด์ œ๋Š” ์ฃผ์„ ์ฒ˜๋ฆฌ๋จ)
#     ...
# }

# server {
#     server_name api.example.com;
#     location /api/v1/ {
#         # CORS ์„ค์ • ์—†์Œ (์ด์ „์—๋Š” http ๋ธ”๋ก์˜ *๊ฐ€ ์ ์šฉ๋˜์—ˆ์Œ)
#         proxy_pass http://backend_service;
#         ...
#     }
# }

# After (nginx/sites-available/api.example.com.conf ํŒŒ์ผ์— ์ถ”๊ฐ€)
# server {
#     listen 443 ssl http2;
#     server_name api.example.com;
#     ...

#     # Preflight ์š”์ฒญ (OPTIONS ๋ฉ”์„œ๋“œ) ์ฒ˜๋ฆฌ
#     location /api/v1/ {
#         if ($request_method = 'OPTIONS') {
#             add_header 'Access-Control-Allow-Origin' 'https://app.example.com';
#             add_header 'Access-Control-Allow-Methods' 'GET, POST, PUT, DELETE, OPTIONS';
#             add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range,X-CSRFToken';
#             add_header 'Access-Control-Max-Age' 1728000; # 20์ผ๊ฐ„ Preflight ๊ฒฐ๊ณผ ์บ์‹ฑ
#             add_header 'Content-Type' 'text/plain; charset=utf-8';
#             add_header 'Content-Length' 0;
#             return 204;
#         }

#         # ์‹ค์ œ ์š”์ฒญ ์ฒ˜๋ฆฌ (GET, POST ๋“ฑ)
#         add_header 'Access-Control-Allow-Origin' 'https://app.example.com';
#         add_header 'Access-Control-Allow-Credentials' 'true'; # ์ž๊ฒฉ ์ฆ๋ช… ํ—ˆ์šฉ (์ค‘์š”!)
#         add_header 'Vary' 'Origin'; # Origin์— ๋”ฐ๋ผ ์บ์‹œ๊ฐ€ ๋‹ค๋ฅด๊ฒŒ ๋™์ž‘ํ•˜๋„๋ก ์„ค์ •
#         proxy_pass http://backend_service;
#         ...
#     }
# }

# ๋ฌด์—‡์ด ์–ด๋–ป๊ฒŒ ๋ณ€ํ–ˆ๋Š”์ง€ ์š”์•ฝ
# ํŠน์ • location ๋ธ”๋ก์— ๋Œ€ํ•ด ํ•„์š”ํ•œ Origin๋งŒ ๋ช…์‹œ์ ์œผ๋กœ ํ—ˆ์šฉํ•˜๊ณ , Preflight ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•œ OPTIONS ๋ฉ”์„œ๋“œ ์‘๋‹ต์„ ์ถ”๊ฐ€ํ–ˆ๋‹ค.
# ์ž๊ฒฉ ์ฆ๋ช…(์ฟ ํ‚ค)์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ Access-Control-Allow-Credentials: true๋ฅผ ์ถ”๊ฐ€ํ•˜๊ณ , ์ด์— ๋งž์ถฐ Access-Control-Allow-Origin์€ ์™€์ผ๋“œ์นด๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ํŠน์ • Origin์„ ๋ช…์‹œํ–ˆ๋‹ค.
  • ์„ฑ๊ณต ์ ๊ฒ€:
  • add_headerย ์ง€์‹œ๋ฌธ์ด ์˜ฌ๋ฐ”๋ฅธย locationย ๋˜๋Š”ย serverย ๋ธ”๋ก์— ์ถ”๊ฐ€๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • Access-Control-Allow-Origin์ด ํ•„์š”ํ•œ Origin๋งŒ ํฌํ•จํ•˜๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • OPTIONSย ๋ฉ”์„œ๋“œ์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๊ฐ€ ํฌํ•จ๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • ์ž๊ฒฉ ์ฆ๋ช…์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐย Access-Control-Allow-Credentials: true๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์„ค์ •๋˜์—ˆ๊ณ ,ย Access-Control-Allow-Origin์ด ์™€์ผ๋“œ์นด๋“œ๊ฐ€ ์•„๋‹Œ ํŠน์ • Origin์œผ๋กœ ์ง€์ •๋˜์—ˆ๋Š”์ง€ ์žฌํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • ์‹ค์ˆ˜ ๋ฐฉ์ง€ ํŒ: ๐Ÿ’ก ์—ฌ๋Ÿฌ Origin์„ ํ—ˆ์šฉํ•ด์•ผ ํ•  ๊ฒฝ์šฐ, ์œ„ ์˜ˆ์‹œ์ฒ˜๋Ÿผ ๋‹จ์ผย add_header์— ์‰ผํ‘œ๋กœ ๊ตฌ๋ถ„ํ•˜์—ฌ ์—ฌ๋Ÿฌ Origin์„ ๋‚˜์—ดํ•˜๋Š” ๊ฒƒ์€ Nginx์—์„œ ์ž‘๋™ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. ๋Œ€์‹ ,ย mapย ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ย ifย ๋ฌธ์„ ํ™œ์šฉํ•˜์—ฌย $http_originย ๋ณ€์ˆ˜์™€ ๋น„๊ตํ•œ ํ›„ ์กฐ๊ฑด๋ถ€๋กœย add_header๋ฅผ ์ถ”๊ฐ€ํ•˜๋Š” ๋ฐฉ์‹์„ ๊ณ ๋ คํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  1. [์„ธ ๋ฒˆ์งธ ๋‹จ๊ณ„: Nginx ์„ค์ • ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ ๋ฐ ์žฌ์‹œ์ž‘]
  • ๋ฌด์—‡์„ ํ•˜๋Š”๊ฐ€?: ๋ณ€๊ฒฝ๋œ Nginx ์„ค์ • ํŒŒ์ผ์— ๋ฌธ๋ฒ•์  ์˜ค๋ฅ˜๊ฐ€ ์—†๋Š”์ง€ ํ™•์ธํ•˜๊ณ , ์„œ๋น„์Šค๋ฅผ ์žฌ์‹œ์ž‘ํ•˜์—ฌ ๋ณ€๊ฒฝ ์‚ฌํ•ญ์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.
  • ์–ด๋–ป๊ฒŒ ํ•˜๋Š”๊ฐ€?: ํ„ฐ๋ฏธ๋„์—์„œ Nginx ๋ช…๋ น์–ด(nginx -t,ย systemctl restart nginx)๋ฅผ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.
# ์˜ˆ์‹œ ์ฝ”๋“œ ๋˜๋Š” ๋ช…๋ น์–ด
# Nginx ์„ค์ • ํŒŒ์ผ ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ
sudo nginx -t

# Nginx ์„œ๋น„์Šค ์žฌ์‹œ์ž‘
sudo systemctl restart nginx
  • ์„ฑ๊ณต ์ ๊ฒ€:ย nginx -tย ๋ช…๋ น ์‹คํ–‰ ์‹œย syntax is ok์™€ย test is successfulย ๋ฉ”์‹œ์ง€๊ฐ€ ์ถœ๋ ฅ๋˜๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.ย systemctl restart nginxย ์ดํ›„, ์„œ๋น„์Šค์— ์ ‘์†ํ•˜์—ฌ ๋ธŒ๋ผ์šฐ์ € ๊ฐœ๋ฐœ์ž ๋„๊ตฌ(F12)์˜ '๋„คํŠธ์›Œํฌ' ํƒญ์—์„œ ์‹ค์ œ ์š”์ฒญ ํ—ค๋”์— CORS ๊ด€๋ จ ํ—ค๋”๊ฐ€ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ํฌํ•จ๋˜์–ด ์žˆ๋Š”์ง€ ํ™•์ธํ•ฉ๋‹ˆ๋‹ค.
  • ์‹ค์ˆ˜ ๋ฐฉ์ง€ ํŒ: โšกย nginx -s reload๋Š” ์„ค์ • ํŒŒ์ผ์„ ๋‹ค์‹œ ๋กœ๋“œํ•˜๋Š” ๊ฒƒ์ด์ง€๋งŒ,ย worker_processes๋‚˜ย listenย ์ง€์‹œ๋ฌธ ๊ฐ™์€ ์ผ๋ถ€ ์„ค์ •์€ย restartย ํ•ด์•ผ๋งŒ ์ ์šฉ๋ฉ๋‹ˆ๋‹ค. ์•ˆ์ „์„ ์œ„ํ•ดย restart๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์„ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ์˜ค๋ฅ˜ ๋ฐœ์ƒ ์‹œย journalctl -xeย ๋ช…๋ น์œผ๋กœ ์‹œ์Šคํ…œ ๋กœ๊ทธ๋ฅผ ํ™•์ธํ•˜์—ฌ ๋ฌธ์ œ์˜ ์›์ธ์„ ํŒŒ์•…ํ•˜์„ธ์š”.


๐Ÿ“ˆ Nginx CORS ์ •์ฑ…: ์ƒ์ƒํ•œ ์„ฑ๊ณต & ์‹คํŒจ ์‚ฌ๋ก€ ๋ถ„์„

  • [์„ฑ๊ณต ์‚ฌ๋ก€: ์•ˆ์ „ํ•œ ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ์—ฐ๋™ ๊ตฌ์ถ•]
  • ๋ฐฐ๊ฒฝ: ๊ธฐ์กด ๋ ˆ๊ฑฐ์‹œ ์‹œ์Šคํ…œ์„ ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ์•„ํ‚คํ…์ฒ˜๋กœ ์ „ํ™˜ํ•˜๋ฉฐ, ๋ฐฑ์—”๋“œ API๋Š”ย api.legacy.com, ์ƒˆ๋กœ์šด ํ”„๋ก ํŠธ์—”๋“œ ์„œ๋น„์Šค๋Š”ย app.newservice.com์— ๋ฐฐํฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ดˆ๊ธฐ์—๋Š” CORS ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์œผ๋‚˜, Nginx๋ฅผ ํ†ตํ•ด ์•ˆ์ „ํ•˜๊ฒŒ ํ•ด๊ฒฐํ•˜๊ณ ์ž ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ์ ์šฉ ์ „๋žต: Nginx API Gateway์—์„œ ๊ฐ ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค์˜ย locationย ๋ธ”๋ก์—ย Access-Control-Allow-Origin์„ ๋ช…์‹œ์ ์œผ๋กœ ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ํŠนํžˆ, ์‚ฌ์šฉ์ž ์ธ์ฆ์ด ํ•„์š”ํ•œย authย ์„œ๋น„์Šค์—๋Š”ย Access-Control-Allow-Origin: https://app.newservice.com๊ณผย Access-Control-Allow-Credentials: true๋ฅผ ํ•จ๊ป˜ ์„ค์ •ํ•˜์—ฌ ํŠน์ • ํ”„๋ก ํŠธ์—”๋“œ์—์„œ๋งŒ ์ž๊ฒฉ ์ฆ๋ช… ๊ธฐ๋ฐ˜์˜ ์š”์ฒญ์„ ํ—ˆ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ํ•ต์‹ฌ ๊ฒฐ๊ณผ:
  • ๋ณด์•ˆ ๊ฐ•ํ™”: ๋ถˆํ•„์š”ํ•œ Origin์œผ๋กœ๋ถ€ํ„ฐ์˜ ์ ‘๊ทผ์„ ์ฐจ๋‹จํ•˜์—ฌ ๋ฌด๋‹จ ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ๋ฐ CSRF ๊ณต๊ฒฉ ์œ„ํ—˜์„ ์ตœ์†Œํ™”ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ์œ ์—ฐํ•œ ์„œ๋น„์Šค ์—ฐ๋™: ์ƒˆ๋กœ์šด ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค์™€ ํ”„๋ก ํŠธ์—”๋“œ ๊ฐ„์˜ ์•ˆ์ •์ ์ธ ํ†ต์‹  ์ฑ„๋„์„ ํ™•๋ณดํ•˜์—ฌ ๊ฐœ๋ฐœ ๋ฐ ๋ฐฐํฌ ์†๋„๋ฅผ ๋†’์˜€์Šต๋‹ˆ๋‹ค.
  • ์‰ฌ์šด ์œ ์ง€๋ณด์ˆ˜: ๊ฐ ์„œ๋น„์Šค๋ณ„๋กœ ํ•„์š”ํ•œ CORS ์ •์ฑ…์„ Nginx์—์„œ ์ค‘์•™ ๊ด€๋ฆฌํ•จ์œผ๋กœ์จ, ์ •์ฑ… ๋ณ€๊ฒฝ ์‹œ ์šฉ์ดํ•˜๊ฒŒ ๋Œ€์‘ํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
  • ์„ฑ๊ณต ์š”์ธ ๋ถ„์„: **"์ตœ์†Œ ๊ถŒํ•œ์˜ ์›์น™"**์„ ์ฒ ์ €ํžˆ ์ง€ํ‚ค๊ณ , ๊ฐ ์„œ๋น„์Šค์˜ ํŠน์„ฑ(์ž๊ฒฉ ์ฆ๋ช… ํ•„์š” ์—ฌ๋ถ€)์— ๋งž์ถฐ CORS ์ •์ฑ…์„ ์„ธ๋ถ„ํ™”ํ•œ ๊ฒƒ์ด ์ฃผํšจํ–ˆ์Šต๋‹ˆ๋‹ค. Nginx์˜ย locationย ๋ธ”๋ก์„ ํ™œ์šฉํ•˜์—ฌ ํŠน์ • ๊ฒฝ๋กœ์—๋งŒ ํ•„์š”ํ•œ CORS ํ—ค๋”๋ฅผ ์ ์šฉํ•จ์œผ๋กœ์จ ์ „์ฒด ์‹œ์Šคํ…œ์˜ ๋ณด์•ˆ์„ ๊ฐ•ํ™”ํ–ˆ์Šต๋‹ˆ๋‹ค.
  • [์‹คํŒจ ์‚ฌ๋ก€: ์•ˆ์ผํ•œ ์™€์ผ๋“œ์นด๋“œ CORS๋กœ ์ธํ•œ ๋ฐ์ดํ„ฐ ์œ ์ถœ ์œ„๊ธฐ]
  • ๋ฐฐ๊ฒฝ: ๋น ๋ฅด๊ฒŒ ๊ฐœ๋ฐœ์„ ์ง„ํ–‰ํ•ด์•ผ ํ•˜๋Š” ์Šคํƒ€ํŠธ์—… ํ™˜๊ฒฝ์—์„œ, ๊ฐœ๋ฐœ์ž๋“ค์ด "์ผ๋‹จ ์ž‘๋™ํ•˜๊ฒŒ ๋งŒ๋“ค์ž"๋Š” ์ƒ๊ฐ์œผ๋กœ Nginx์˜ย httpย ๋ธ”๋ก์—ย add_header 'Access-Control-Allow-Origin' '*';๋ฅผ ์„ค์ •ํ•˜๊ณ  ๋ฐฐํฌํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฐฑ์—”๋“œ API๋Š” ์‚ฌ์šฉ์ž ํ”„๋กœํ•„ ์ •๋ณด๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์—”๋“œํฌ์ธํŠธ(GET /user/profile)๋ฅผ ํฌํ•จํ•˜๊ณ  ์žˆ์—ˆ์œผ๋ฉฐ, ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž์—๊ฒŒ๋งŒ ์ ‘๊ทผ์ด ํ—ˆ์šฉ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
  • ์‹คํŒจ ์š”์ธ:
  • ๊ณผ๋„ํ•œ ๊ถŒํ•œ ๋ถ€์—ฌ:ย Access-Control-Allow-Origin: *ย ์„ค์ •์€ ๋ชจ๋“  ์›น์‚ฌ์ดํŠธ๊ฐ€ ์ธ์ฆ๋œ ์‚ฌ์šฉ์ž์˜ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ํ†ตํ•ด ํ•ด๋‹น API์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ํ—ˆ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ์ž๊ฒฉ ์ฆ๋ช…๊ณผ์˜ ๊ฒฐํ•ฉ: ๋น„๋กย Access-Control-Allow-Credentials๋Š” ์—†์—ˆ์ง€๋งŒ,ย *ย ์„ค์ • ์ž์ฒด๋งŒ์œผ๋กœ๋„ ๊ณต๊ฒฉ์ž๊ฐ€ ์•…์˜์ ์ธ ์›น์‚ฌ์ดํŠธ(evil.com)๋ฅผ ํ†ตํ•ด ์‚ฌ์šฉ์ž์˜ ๋ธŒ๋ผ์šฐ์ €์—์„œย GET /user/profileย ์š”์ฒญ์„ ๋ณด๋‚ด๊ณ , ๊ทธ ์‘๋‹ต์œผ๋กœ ๋ฐ›์€ ์‚ฌ์šฉ์ž ํ”„๋กœํ•„ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด๊ฐˆ ์ˆ˜ ์žˆ๋Š” ์‹ฌ๊ฐํ•œ ์ทจ์•ฝ์ ์ด ๋ฐœ์ƒํ–ˆ์Šต๋‹ˆ๋‹ค. (๋ธŒ๋ผ์šฐ์ €๋Š”ย *์ธ ๊ฒฝ์šฐ ์ž๊ฒฉ ์ฆ๋ช…์„ ๋ณด๋‚ด์ง€ ์•Š์ง€๋งŒ,ย simple request์— ๋Œ€ํ•œ ์‘๋‹ต์€ ์ฝ์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.)
  • ์ธ์‹ ๋ถ€์กฑ: ๊ฐœ๋ฐœํŒ€์€ CORS ์˜ค๋ฅ˜๋ฅผ ํ•ด๊ฒฐํ–ˆ๋‹ค๋Š” ์•ˆ๋„๊ฐ์— ์ด ์„ค์ •์ด ๊ฐ€์ ธ์˜ฌ ์ž ์žฌ์  ์œ„ํ—˜์„ ์ œ๋Œ€๋กœ ์ธ์ง€ํ•˜์ง€ ๋ชปํ–ˆ์Šต๋‹ˆ๋‹ค.
  • ์–ป์€ ๊ตํ›ˆ: ๋ณด์•ˆ ์ปจ์„คํŒ… ์ค‘ ์ด ์ทจ์•ฝ์ ์ด ๋ฐœ๊ฒฌ๋˜์—ˆ๊ณ , ์ฆ‰์‹œย Access-Control-Allow-Origin: *๋ฅผ ์ œ๊ฑฐํ•˜๊ณ  ํŠน์ • Origin๋งŒ ํ—ˆ์šฉํ•˜๋„๋ก ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด ๊ฒฝํ—˜์„ ํ†ตํ•ด ๊ฐœ๋ฐœํŒ€์€ **"๋น ๋ฅธ ๊ฐœ๋ฐœ๋งŒํผ ์ค‘์š”ํ•œ ๊ฒƒ์€ ์•ˆ์ „ํ•œ ๊ฐœ๋ฐœ"**์ด๋ผ๋Š” ๊ตํ›ˆ์„ ์–ป์—ˆ์œผ๋ฉฐ, ๋ชจ๋“  API ์—”๋“œํฌ์ธํŠธ์— ๋Œ€ํ•ด ์ฒ ์ €ํ•œ ๋ณด์•ˆ ๊ฒ€ํ†  ํ”„๋กœ์„ธ์Šค๋ฅผ ๋„์ž…ํ•˜๊ฒŒ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.ย Access-Control-Allow-Origin: *๋Š” ๋งค์šฐ ์œ„ํ—˜ํ•˜๋ฉฐ, ํŠนํžˆ ์ธ์ฆ์ด ํ•„์š”ํ•œ API์—์„œ๋Š” ์ ˆ๋Œ€ ์‚ฌ์šฉํ•ด์„œ๋Š” ์•ˆ ๋œ๋‹ค๋Š” ์ ์„ ๊นจ๋‹ฌ์•˜์Šต๋‹ˆ๋‹ค.


โ“ ์ž์ฃผ ๋ฌป๋Š” ์งˆ๋ฌธ(FAQ)

  • Q1.ย Access-Control-Allow-Origin: *๋Š” ์™œ ์œ„ํ—˜ํ•œ๊ฐ€์š”?
  • A1. ๋ชจ๋“  ์›น์‚ฌ์ดํŠธ๊ฐ€ ๊ท€ํ•˜์˜ ์„œ๋น„์Šค API์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก ํ—ˆ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค. ํŠนํžˆ ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธ๋˜์–ด ์žˆ๋Š” ์ƒํƒœ๋ผ๋ฉด, ์•…์˜์ ์ธ ์‚ฌ์ดํŠธ๊ฐ€ ์‚ฌ์šฉ์ž์˜ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ํ†ตํ•ด ๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ์–ด๊ฐ€๊ฑฐ๋‚˜ ์›์น˜ ์•Š๋Š” ์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋„๋ก ์œ ๋„ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Q2.ย Access-Control-Allow-Origin์„ ์—ฌ๋Ÿฌ ๊ฐœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‚˜์š”?
  • A2. Nginx์˜ย add_headerย ์ง€์‹œ๋ฌธ์€ ๋‹จ์ผ ๊ฐ’๋งŒ ๊ฐ€์งˆ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์—ฌ๋Ÿฌ Origin์„ ํ—ˆ์šฉํ•˜๋ ค๋ฉดย ifย ๋ฌธ๊ณผย $http_originย ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜,ย mapย ๋ชจ๋“ˆ์„ ํ™œ์šฉํ•˜์—ฌ ๋™์ ์œผ๋กœ Origin์„ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • Q3.ย OPTIONSย ์š”์ฒญ(Preflight)์€ ๋ฌด์—‡์ด๊ณ  ์™œ ํ•„์š”ํ•œ๊ฐ€์š”?
  • A3. ์‹ค์ œ ์š”์ฒญ์„ ๋ณด๋‚ด๊ธฐ ์ „์— ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์„œ๋ฒ„์—๊ฒŒ "์ด๋Ÿฐ ์š”์ฒญ์„ ๋ณด๋‚ด๋„ ๋ ๊นŒ์š”?"๋ผ๊ณ  ๋ฌป๋Š” ์ผ์ข…์˜ ์‚ฌ์ „ ํ™•์ธ ์š”์ฒญ์ž…๋‹ˆ๋‹ค.ย POST,ย PUT,ย DELETE์™€ ๊ฐ™์€ ๋ฉ”์„œ๋“œ๋‚˜ ์ปค์Šคํ…€ ํ—ค๋”๋ฅผ ํฌํ•จํ•˜๋Š” ์š”์ฒญ์ผ ๊ฒฝ์šฐ ๋ณด์•ˆ์„ ์œ„ํ•ด ํ•„์ˆ˜์ ์œผ๋กœ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค. ์„œ๋ฒ„๋Š”ย OPTIONSย ์š”์ฒญ์— ๋Œ€ํ•ด ํ—ˆ์šฉ ์—ฌ๋ถ€๋ฅผ ์‘๋‹ตํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • Q4.ย Access-Control-Allow-Credentials: true๋Š” ์–ธ์ œ ์‚ฌ์šฉํ•ด์•ผ ํ•˜๋‚˜์š”?
  • A4. ์ฟ ํ‚ค, HTTP ์ธ์ฆ ํ—ค๋”, ํด๋ผ์ด์–ธํŠธ SSL ์ธ์ฆ์„œ์™€ ๊ฐ™์€ ์‚ฌ์šฉ์ž ์ž๊ฒฉ ์ฆ๋ช…์„ ํฌํ•จํ•˜๋Š” ์š”์ฒญ์„ ํ—ˆ์šฉํ•  ๋•Œ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.ย ์ด ๊ฒฝ์šฐย Access-Control-Allow-Origin: *๋Š” ์ ˆ๋Œ€ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์œผ๋ฉฐ, ๋ฐ˜๋“œ์‹œ ํŠน์ • Origin์„ ๋ช…์‹œํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
  • Q5. CORS ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์–ด๋–ป๊ฒŒ ๋””๋ฒ„๊น…ํ•ด์•ผ ํ•˜๋‚˜์š”?
  • A5. ๋ธŒ๋ผ์šฐ์ € ๊ฐœ๋ฐœ์ž ๋„๊ตฌ(F12)์˜ '๋„คํŠธ์›Œํฌ' ํƒญ์„ ์—ด๊ณ , ์‹คํŒจํ•œ ์š”์ฒญ์„ ํด๋ฆญํ•œ ํ›„ 'ํ—ค๋”' ์„น์…˜์„ ํ™•์ธํ•˜์„ธ์š”. ํŠนํžˆ '์‘๋‹ต ํ—ค๋”'์—ย Access-Control-Allow-Originย ๋ฐ ๋‹ค๋ฅธ CORS ๊ด€๋ จ ํ—ค๋”๋“ค์ด ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ํฌํ•จ๋˜์–ด ์žˆ๋Š”์ง€, ๊ทธ๋ฆฌ๊ณ  ์š”์ฒญ 'Origin'๊ณผ ์ผ์น˜ํ•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.
  • Q6. Nginx์—์„œ ํŠน์ • IP ์ฃผ์†Œ์—๋งŒ CORS๋ฅผ ํ—ˆ์šฉํ•  ์ˆ˜ ์žˆ๋‚˜์š”?
  • A6.ย if ($remote_addr = 'ํŠน์ •IP')์™€ ๊ฐ™์€ ์กฐ๊ฑด๋ฌธ์œผ๋กœย add_header๋ฅผ ์ œ์–ดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ํ•˜์ง€๋งŒ ์ด๋Š” ํด๋ผ์ด์–ธํŠธ์˜ IP ์ฃผ์†Œ๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํ•˜๋ฏ€๋กœ, ํ”„๋ก์‹œ ํ™˜๊ฒฝ์—์„œ๋Š”ย X-Forwarded-Forย ํ—ค๋”๋ฅผ ํ™œ์šฉํ•˜๋Š” ๋“ฑ ์ถ”๊ฐ€์ ์ธ ๊ณ ๋ ค๊ฐ€ ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค. ์ผ๋ฐ˜์ ์œผ๋กœ CORS๋Š” Origin(๋„๋ฉ”์ธ) ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.
  • Q7. CORS ์ •์ฑ…์„ ์„ค์ •ํ–ˆ๋Š”๋ฐ๋„ ์—ฌ์ „ํžˆ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.
  • A7. ๋‹ค์Œ์„ ํ™•์ธํ•ด ๋ณด์„ธ์š”: Nginx ์„ค์ • ์žฌ๋กœ๋“œ/์žฌ์‹œ์ž‘ ์—ฌ๋ถ€, ๋ธŒ๋ผ์šฐ์ € ์บ์‹œ ๋ฌธ์ œ(ํ•˜๋“œ ์ƒˆ๋กœ๊ณ ์นจ),ย OPTIONSย ์š”์ฒญ ์ฒ˜๋ฆฌ ๋ˆ„๋ฝ,ย Access-Control-Allow-Origin์— ์˜คํƒ€๊ฐ€ ์žˆ๊ฑฐ๋‚˜ ํ”„๋กœํ† ์ฝœ(http/https)์ด ์ผ์น˜ํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ,ย Access-Control-Allow-Credentials์™€ย *์˜ ๋™์‹œ ์‚ฌ์šฉ ์—ฌ๋ถ€.


๐Ÿ’ก Nginx CORS ์ •์ฑ…: ์‹ค์ „ ์šด์˜ ํŒ & ์ฃผ์˜์‚ฌํ•ญ

  • [ํŒ 1:ย Vary: Originย ํ—ค๋” ์ถ”๊ฐ€๋กœ ์บ์‹œ ๋ฌด๊ฒฐ์„ฑ ํ™•๋ณด]: ๐ŸŽฏ Nginx์—์„œ ํ”„๋ก์‹œ ์บ์‹ฑ์„ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด,ย add_header Vary Origin;์„ ์ถ”๊ฐ€ํ•˜์—ฌย Originย ํ—ค๋” ๊ฐ’์— ๋”ฐ๋ผ ์‘๋‹ต์„ ์บ์‹œํ•˜๋„๋ก ํ•˜์„ธ์š”. ์ด๋Š” ๋‹ค๋ฅธ Origin์˜ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ด์ „ Origin์˜ ์บ์‹œ๋œ ์‘๋‹ต์„ ๋ฐ›์•„ CORS ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ํ•ฉ๋‹ˆ๋‹ค.
  • [ํŒ 2: Preflight ์š”์ฒญ์˜ย Access-Control-Max-Ageย ํ™œ์šฉ]: ๐Ÿš€ย OPTIONSย ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต์—ย add_header 'Access-Control-Max-Age' 1728000;ย (์ดˆ ๋‹จ์œ„, ์˜ˆ: 20์ผ)๋ฅผ ์ถ”๊ฐ€ํ•˜๋ฉด, ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํ•ด๋‹น ๊ธฐ๊ฐ„ ๋™์•ˆ Preflight ์š”์ฒญ ๊ฒฐ๊ณผ๋ฅผ ์บ์‹œํ•˜์—ฌ ๋ถˆํ•„์š”ํ•œย OPTIONSย ์š”์ฒญ์„ ์ค„์ด๊ณ  ์„ฑ๋Šฅ์„ ํ–ฅ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • [ํŒ 3: ๋™์  Origin ํ—ˆ์šฉ์„ ์œ„ํ•œย mapย ๋ชจ๋“ˆ ์‚ฌ์šฉ]: โš™๏ธ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ํŠน์ • Origin์„ ํ—ˆ์šฉํ•ด์•ผ ํ•˜์ง€๋งŒย ifย ๋ฌธ์˜ ๋ณต์žก์„ฑ์„ ํ”ผํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, Nginx์˜ย mapย ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•˜์—ฌย $http_originย ๋ณ€์ˆ˜์— ๋”ฐ๋ผย Access-Control-Allow-Originย ๊ฐ’์„ ๋™์ ์œผ๋กœ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
# http ๋ธ”๋ก ๋‚ด์— ์ •์˜
map $http_origin $cors_origin {
    default "";
    "https://app.example.com" "https://app.example.com";
    "https://admin.example.com" "https://admin.example.com";
}

# server ๋˜๋Š” location ๋ธ”๋ก ๋‚ด์—์„œ ์‚ฌ์šฉ
# if ($cors_origin ~ ".+") { # $cors_origin์ด ๋น„์–ด์žˆ์ง€ ์•Š๋‹ค๋ฉด
#     add_header 'Access-Control-Allow-Origin' $cors_origin;
# }
  • [ํŒ 4: ๋ณด์•ˆ ํ—ค๋”์™€ CORS ์ •์ฑ…์˜ ์กฐํ™”]: ๐Ÿ›ก๏ธ CORS ์ •์ฑ… ์™ธ์—๋„ย X-Frame-Options,ย X-Content-Type-Options,ย X-XSS-Protection,ย Content-Security-Policyย ๋“ฑ ๋‹ค๋ฅธ ๋ณด์•ˆ ํ—ค๋”๋“ค์„ ํ•จ๊ป˜ ์„ค์ •ํ•˜์—ฌ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์ „๋ฐ˜์ ์ธ ๋ณด์•ˆ ์ˆ˜์ค€์„ ๋†’์ด๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค. Nginxย nginx.confย ํŒŒ์ผ์—๋Š” ์ด๋ฏธ ์ด๋Ÿฌํ•œ ๋ณด์•ˆ ํ—ค๋” ์„ค์ •๋“ค์ด ํฌํ•จ๋˜์–ด ์žˆ์œผ๋‹ˆ ์ฐธ๊ณ ํ•˜์„ธ์š”.


๐Ÿ”š ๊ฒฐ๋ก  ๋ฐ ๋‹ค์Œ ๋‹จ๊ณ„

  • [ํ•ต์‹ฌ ์š”์•ฝ]: Nginx CORS ์ •์ฑ…์€ ๋‹จ์ˆœํ•œ ์„ค์ • ์˜ค๋ฅ˜ ๋ฌธ์ œ๊ฐ€ ์•„๋‹Œ, ์›น ๋ณด์•ˆ์˜ ํ•ต์‹ฌ์ ์ธ ๋ถ€๋ถ„์ž…๋‹ˆ๋‹ค.ย Access-Control-Allow-Origin: *์™€ ๊ฐ™์€ ์™€์ผ๋“œ์นด๋“œ ์‚ฌ์šฉ์€ ์น˜๋ช…์ ์ธ ๋ณด์•ˆ ์ทจ์•ฝ์ ์œผ๋กœ ์ด์–ด์งˆ ์ˆ˜ ์žˆ์Œ์„ ์ดํ•ดํ•˜๊ณ , ํ•ญ์ƒ ์ตœ์†Œ ๊ถŒํ•œ์˜ ์›์น™์— ๋”ฐ๋ผ ํŠน์ • Origin๋งŒ์„ ํ—ˆ์šฉํ•˜๋„๋ก ์‹ ์ค‘ํ•˜๊ฒŒ ์„ค์ •ํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.ย OPTIONSย Preflight ์š”์ฒญ ์ฒ˜๋ฆฌ,ย Access-Control-Allow-Credentialsย ์‚ฌ์šฉ ์‹œ ์ฃผ์˜์‚ฌํ•ญ ๋“ฑ์„ ๊ณ ๋ คํ•˜์—ฌ ์•ˆ์ „ํ•˜๊ณ  ํšจ์œจ์ ์ธ ์›น ์„œ๋น„์Šค๋ฅผ ๊ตฌ์ถ•ํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š”ํ•ฉ๋‹ˆ๋‹ค.
  • [๋‹ค์Œ ๋‹จ๊ณ„ ์ œ์•ˆ]:
  1. Nginx ๊ณต์‹ ๋ฌธ์„œ ์‹ฌํ™” ํ•™์Šต:ย ngx_http_headers_moduleย ์™ธ์—๋„ย ngx_http_map_module,ย ngx_http_core_moduleย ๋“ฑ์„ ํ•™์Šตํ•˜์—ฌ Nginx ์„ค์ •์˜ ๊นŠ์ด๋ฅผ ๋”ํ•ด๋ณด์„ธ์š”.
  2. ๋ณด์•ˆ ์ปจ์„คํŒ…/๊ฐ์‚ฌ: ์„œ๋น„์Šค๊ฐ€ ์„ฑ์žฅํ•จ์— ๋”ฐ๋ผ ์ •๊ธฐ์ ์ธ ์›น ๋ณด์•ˆ ๊ฐ์‚ฌ ๋˜๋Š” ์ปจ์„คํŒ…์„ ํ†ตํ•ด ์ž ์žฌ์  ์ทจ์•ฝ์ ์„ ์‚ฌ์ „์— ํŒŒ์•…ํ•˜๊ณ  ๊ฐœ์„ ํ•˜๋Š” ๋…ธ๋ ฅ์„ ๊ธฐ์šธ์ด์„ธ์š”.
  3. ๊ด€๋ จ ํ”„๋กœ์ ํŠธ ์ฐธ์—ฌ: GitHub ๋“ฑ์—์„œ ์˜คํ”ˆ ์†Œ์Šค Nginx ์„ค์ • ํ”„๋กœ์ ํŠธ๋ฅผ ์‚ดํŽด๋ณด๋ฉฐ ๋‹ค๋ฅธ ์ „๋ฌธ๊ฐ€๋“ค์˜ ์„ค์ • ๋ฐฉ์‹์„ ๋ฐฐ์šฐ๊ณ , ์ž์‹ ์˜ ๊ฒฝํ—˜์„ ๊ณต์œ ํ•˜๋ฉฐ ํ•จ๊ป˜ ์„ฑ์žฅํ•ด ๋ณด์„ธ์š”.

ย 

๋ชฉ์ฐจ
๋ชฉ์ฐจ๋ฅผ ๋ถˆ๋Ÿฌ์˜ค๋Š” ์ค‘...

๋Œ“๊ธ€

Loading...

๋Œ“๊ธ€ ๋กœ๋”ฉ ์ค‘...

๊ตฌ๊ธ€ ๊ฒ€์ƒ‰