infra & network

SOP & CORS๋ž€?

devJK93 2024. 7. 31.

๐Ÿ“’ ๋™์ผ ์ถœ์ฒ˜ ์ •์ฑ… (Same-Origin Policy, SOP)

๋ธŒ๋ผ์šฐ์ €๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ SOP ์ •์ฑ…์„ ๋”ฐ๋ฅด๊ณ  ์žˆ๋‹ค.

SOP๋Š” 2011๋…„ RFC 6454์—์„œ ๋“ฑ์žฅํ•œ ๋ณด์•ˆ ์ •์ฑ…์œผ๋กœ "๊ฐ™์€ ์ถœ์ฒ˜์—์„œ๋งŒ ๋ฆฌ์†Œ์Šค๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋‹ค"๋ผ๋Š” ๊ทœ์น™์„ ๊ฐ€์ง„ ์ •์ฑ….

 

SOP์˜ ๋“ฑ์žฅ๋ฐฐ๊ฒฝ์€ ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

 

1. ๋ณด์•ˆ ๊ฐ•ํ™”:

  • XSS (Cross-Site Scripting) ๋ฐฉ์ง€: ๋™์ผ ์ถœ์ฒ˜ ์ •์ฑ…์€ ์•…์„ฑ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์‚ฌ์šฉ์ž ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‹คํ–‰๋˜์–ด ๋‹ค๋ฅธ ์‚ฌ์ดํŠธ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ํ›”์น˜๊ฑฐ๋‚˜ ์กฐ์ž‘ํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€.
  • CSRF (Cross-Site Request Forgery) ๋ฐฉ์ง€: ๋™์ผ ์ถœ์ฒ˜ ์ •์ฑ…์€ ๊ณต๊ฒฉ์ž๊ฐ€ ์‚ฌ์šฉ์ž์˜ ์ธ์ฆ ์ •๋ณด๋ฅผ ์ด์šฉํ•ด ๋‹ค๋ฅธ ์‚ฌ์ดํŠธ์— ๋ฌด๋‹จ์œผ๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ๊ฒƒ์„ ๋ง‰๋Š”๋‹ค.

2. ๋ฐ์ดํ„ฐ ๋ณดํ˜ธ:

  • ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์ข…์ข… ๋ฏผ๊ฐํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋‹ค๋ฃฌ๋‹ค. ๋™์ผ ์ถœ์ฒ˜ ์ •์ฑ…์€ ํ•œ ์‚ฌ์ดํŠธ์˜ ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋‹ค๋ฅธ ์‚ฌ์ดํŠธ์˜ ๋ฐ์ดํ„ฐ๋ฅผ ์ฝ๋Š” ๊ฒƒ์„ ์ œํ•œํ•จ์œผ๋กœ์จ ์‚ฌ์šฉ์ž ๋ฐ์ดํ„ฐ๋ฅผ ๋ณดํ˜ธํ•œ๋‹ค.

3. ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ํ†ต์‹ :

  • ๋™์ผ ์ถœ์ฒ˜ ์ •์ฑ…์€ ์›น ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํŠน์ • ์ถœ์ฒ˜์—์„œ๋งŒ ์ž์›์„ ์š”์ฒญํ•˜๊ณ  ์‘๋‹ต์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ํ•จ์œผ๋กœ์จ, ํ†ต์‹ ์˜ ์‹ ๋ขฐ์„ฑ์„ ๋†’์ธ๋‹ค. ์ด๋Š” ํŠนํžˆ AJAX ์š”์ฒญ์—์„œ ์ค‘์š”.

4. ํ‘œ์ค€ํ™”:

  • ์›น ๋ณด์•ˆ ํ‘œ์ค€ํ™”์˜ ์ผํ™˜์œผ๋กœ, ๋™์ผ ์ถœ์ฒ˜ ์ •์ฑ…์€ ๋ธŒ๋ผ์šฐ์ €์™€ ์›น ๊ฐœ๋ฐœ์ž ๊ฐ„์˜ ๊ณตํ†ต๋œ ๋ณด์•ˆ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์ œ๊ณตํ•œ๋‹ค. ์ด๋ฅผ ํ†ตํ•ด ๋ณด์•ˆ ๊ด€๋ จ ํ˜ผ๋ž€์„ ์ค„์ด๊ณ , ์ผ๊ด€๋œ ๋ณด์•ˆ ์ •์ฑ…์„ ์œ ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

์ฃผ๋œ ์ด์œ ๋Š” ์›น ๋ณด์•ˆ์ด๋ฉฐ XSS, CRSF ๊ณต๊ฒฉ์— ๋Œ€ํ•ด์„œ๋Š” ๋‹ค์Œ ๊ธ€์—์„œ ์„ค๋ช… ์˜ˆ์ •.

 

๐Ÿ“˜ ์ถœ์ฒ˜ (Origin)

SOP์—์„œ ๋งํ•˜๋Š” '๊ฐ™์€ ์ถœ์ฒ˜'๋ž€ ๋ฌด์—‡์„ ์˜๋ฏธํ• ๊นŒ?

์›น์—์„œ ๋งํ•˜๋Š” ์ถœ์ฒ˜ (Origin)๋Š” URL์˜ ์Šคํ‚ค๋งˆ(ํ”„๋กœํ† ์ฝœ), ํ˜ธ์ŠคํŠธ(๋„๋ฉ”์ธ), ํฌํŠธ ์ด 3๊ฐ€์ง€๋กœ ์ •์˜๋œ๋‹ค.

Origin

 

๋™์ผ ์ถœ์ฒ˜ ์˜ˆ์‹œ

  • http://example.com/hello ์™€ http://example.com/bye → ํ”„๋กœํ† ์ฝœ, ๋„๋ฉ”์ธ, ํฌํŠธ๊ฐ€ ๋ชจ๋‘ ๊ฐ™์œผ๋ฏ€๋กœ ๋™์ผ ์ถœ์ฒ˜์ด๋‹ค.
  • http://example.com ์™€ https://example.com → ๊ฐ™์€ ๋ฆฌ์†Œ์Šค๋ฅผ ๊ฐ€๋ฆฌํ‚ค๊ณ  ์žˆ์ง€๋งŒ, ํ”„๋กœํ† ์ฝœ์ด ๋‹ค๋ฅด๋ฏ€๋กœ ๋™์ผ ์ถœ์ฒ˜๊ฐ€ ์•„๋‹ˆ๋‹ค.
  • http://example.com ์™€ http://example.com:80 → ์–ผํ•๋ณด๋ฉด ๋‹ค๋ฅธ ์ถœ์ฒ˜๊ฐ™์ง€๋งŒ, ์ „์ž์˜ ๊ฒฝ์šฐ http ์˜ ๊ธฐ๋ณธ ํฌํŠธ์ธ 80์ด ์ƒ๋žต๋œ ํ˜•ํƒœ์ด๋ฏ€๋กœ ์ด๋Š” ๊ฐ™์€ ์ถœ์ฒ˜.

๋™์ผ ์ถœ์ฒ˜๋ผ๋ฆฌ ์š”์ฒญ์„ ์ฃผ๊ณ  ๋ฐ›์•„์•ผ์ง€๋งŒ SOP๋ฅผ ์ง€ํ‚ค๋Š” ๊ฒƒ์ด๋‹ค.

์˜ˆ์ „์—๋Š” ์ถœ์ฒ˜๊ฐ€ ๋‹ค๋ฅธ ๊ณณ์œผ๋กœ ์š”์ฒญํ•˜๋Š” ๊ฒƒ ์ž์ฒด๋ฅผ ์•…์˜์  ํ–‰์œ„๋กœ ๊ฐ„์ฃผํ–ˆ๋‹ค(CSRF, XSS ๋“ฑ).

์™œ๋ƒํ•˜๋ฉด ์˜ˆ์ „์˜ ์›น์€ ํ”„๋ก ํŠธ์—”๋“œ ๋ ˆ์ด์–ด์™€ ๋ฐฑ์—”๋“œ ๋ ˆ์ด์–ด๋ฅผ ๋ณ„๋„๋กœ ๊ตฌ์„ฑํ•˜์ง€ ์•Š๊ณ  ์„œ๋ฒ„๊ฐ€ ์ง์ ‘ ์š”์ฒญ ์ฒ˜๋ฆฌ์˜ ๊ฒฐ๊ณผ๋ฅผ HTML ๋ฌธ์„œ๋กœ ๋งŒ๋“ค์–ด ํด๋ผ์ด์–ธํŠธ์— ์‘๋‹ตํ•˜๋Š” ํ˜•์‹์ด์—ˆ๊ธฐ ๋•Œ๋ฌธ.

<html>
  <head>
    <title> PHP example </title>
  </head>
  <body>
    <?php
      $i = 1;

      while($i<=10)
      {
        echo $i."๋ฒˆ์งธ<br />";
        $i++;
      }
    ?>
  </body>
</html>

 

๐Ÿ“— ๊ต์ฐจ ์ถœ์ฒ˜ ๋ฆฌ์†Œ์Šค ๊ณต์œ  (Cross-Origin Resource Sharing, CORS)

์„œ๋น„์Šค์ค‘์ธ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํ”„๋ก ํŠธ๋‹จ์—์„œ ์ œ 3์ž๊ฐ€ ์ œ๊ณตํ•˜๋Š” API๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•ด์•ผํ•˜๋Š” ๋“ฑ(๊ฒฐ์ œ API, ์ง€๋„ API, SNS API, ๋‚ ์”จ API, ๋ฒˆ์—ญ API, ๊ฒ€์ƒ‰ ์—”์ง„, ๋ฐ์ดํ„ฐ ์‹œ๊ฐํ™” API, ๋จธ์‹  ๋Ÿฌ๋‹ ๋ฐ AI API, ์ธ์ฆ ๋ฐ ์‚ฌ์šฉ์ž ๊ด€๋ฆฌ API ๋“ฑ..) ์ ์  ์›น ์„œ๋น„์Šค์—์„œ ์š”๊ตฌ๋˜๋Š” ๊ธฐ๋Šฅ๋“ค์ด ๋Š˜์–ด๋‚ฌ๋‹ค. ํ•˜์ง€๋งŒ SOP๋ผ๋Š” ๋ธŒ๋ผ์šฐ์ € ์ •์ฑ… ๋•Œ๋ฌธ์— ๊ธฐ๋ณธ์ ์œผ๋กœ ์ด๋Š” ์•…์˜์ ์ธ ํ–‰์œ„๋กœ ๊ฐ„์ฃผ๋˜์—ˆ๋‹ค. ๋”ฐ๋ผ์„œ ํ˜ธ์ถœํ•˜๊ณ  ์‹ถ์€ API๋ฅผ ์šฐ๋ฆฌ์˜ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๋ฅผ ํ•œ๋ฒˆ ๊ฑฐ์ณ์„œ ํ˜ธ์ถœํ•˜๊ฑฐ๋‚˜, JSONP ๋ผ๋Š” ๊ธฐ์ˆ ๋„ ๋“ฑ์žฅํ–ˆ์ง€๋งŒ ๊ทผ๋ณธ์ ์ธ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ํ•„์š”ํ–ˆ๋‹ค.

 

์ด๋Ÿฐ ๋ฐฐ๊ฒฝ์œผ๋กœ CORS๊ฐ€ ๋“ฑ์žฅํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. ๋ฆฌ์†Œ์Šค ํ˜ธ์ถœ์ด ํ—ˆ์šฉ๋œ ์ถœ์ฒ˜๋ฅผ ์„œ๋ฒ„๊ฐ€ ๋ช…์‹œํ•ด๋†“์œผ๋ฉด, ์ถœ์ฒ˜๊ฐ€ ๋‹ค๋ฅด๋”๋ผ๋„ ์š”์ฒญ๊ณผ ์‘๋‹ต์„ ์ฃผ๊ณ  ๋ฐ›์„ ์ˆ˜ ์žˆ๋„๋ก ๋งŒ๋“ค์–ด๋†“์€ ์ •์ฑ…์ด ๋ฐ”๋กœ CORS์ด๋‹ค.

 

๐Ÿ“™ CORS ์ ‘๊ทผ ์ œ์–ด ์‹œ๋‚˜๋ฆฌ์˜ค

๐Ÿ“ 1. ๋‹จ์ˆœ ์š”์ฒญ (Simple Requests)

https://www.baeldung.com/cs/cors-preflight-requests

 

๋ธŒ๋ผ์šฐ์ €๋Š” ๋‹ค๋ฅธ ์ถœ์ฒ˜๋กœ์˜ ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ ์ž๋™์œผ๋กœ HTTP ํ—ค๋”์— Origin ์„ ์ถ”๊ฐ€ํ•˜์—ฌ ๋ณด๋‚ธ๋‹ค.

Origin: https://foo.example

 

์ด ์‘๋‹ต์„ ๋ฐ›์€ ์„œ๋ฒ„๋Š” ์‘๋‹ต ํ—ค๋”์— Access-Control-Allow-Origin ์„ ์‹ค์–ด ๋ณด๋‚ธ๋‹ค. ์ด ํ—ค๋”์—๋Š” ํ—ˆ๊ฐ€๋œ ์ถœ์ฒ˜ ์ •๋ณด๊ฐ€ ๋‹ด๊ฒจ์žˆ๋‹ค. ์™€์ผ๋“œ์นด๋“œ๋ฅผ ์‚ฌ์šฉํ•ด์„œ ๋ชจ๋“  ์ถœ์ฒ˜๋ฅผ ํ—ˆ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

Access-Control-Allow-Origin: *

 

๋ธŒ๋ผ์šฐ์ €๋Š” ์š”์ฒญ์˜ Origin ํ—ค๋”์— ๋‹ด๊ธด ์ถœ์ฒ˜ ์ •๋ณด๊ฐ€ ์‘๋‹ต์˜ Access-Control-Allow-Origin ํ—ค๋”์— ๋‹ด๊ฒจ์žˆ์œผ๋ฉด ํ•ด๋‹น ์š”์ฒญ์„ ์•ˆ์ „ํ•˜๋‹ค๊ณ  ๊ฐ„์ฃผํ•˜๊ณ  ์‘๋‹ต์„ ๊ฐ€์ ธ์˜จ๋‹ค. ๋งŒ์•ฝ ๊ทธ๋ ‡์ง€ ์•Š๋‹ค๋ฉด, ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ํ•ด๋‹น ์‘๋‹ต์„ ์ž„์˜๋กœ ํŒŒ๊ธฐํ•˜๊ณ  ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ์‘๋‹ต์˜ ๋‚ด์šฉ์„ ์ „๋‹ฌํ•˜์ง€ ์•Š๋Š”๋‹ค.

 

โ“ ๋‹จ์ˆœ ์š”์ฒญ์˜ ์กฐ๊ฑด

 

ํ•˜์ง€๋งŒ ์š”์ฒญ์ด ๋‹จ์ˆœ ์š”์ฒญ์œผ๋กœ ์ทจ๊ธ‰๋˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ์•„๋ž˜์˜ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•ด์•ผํ•œ๋‹ค.

  • GET, POST, HEAD ๋ฉ”์„œ๋“œ๋งŒ ํ—ˆ์šฉ๋œ๋‹ค.
  • Accept, Accept-Language, Content-Language, Content-Type ํ—ค๋”๋งŒ ํ—ˆ์šฉ๋œ๋‹ค.
  • Content-Type ๋Š” application/x-www-form-urlencoded, multipart/form-data, text/plain ์ด ์„ธ๊ฐ€์ง€ ๊ฐ’๋งŒ ํ—ˆ์šฉ๋œ๋‹ค.
  • ์š”์ฒญ์— ์‚ฌ์šฉ๋œ XMLHttpRequestUpload ๊ฐ์ฒด์—๋Š” ์ด๋ฒคํŠธ ๋ฆฌ์Šค๋„ˆ๊ฐ€ ๋“ฑ๋ก๋˜์–ด ์žˆ์ง€ ์•Š๋‹ค์ด๋“ค์€ XMLHttpRequest.upload ํ”„๋กœํผํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ ‘๊ทผํ•œ๋‹ค.
  • ์š”์ฒญ์— ReadableStream ๊ฐ์ฒด๊ฐ€ ์‚ฌ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค.

๋‹จ์ˆœ ์š”์ฒญ์€ ํ”ํ•˜์ง€ ์•Š๋‹ค.

๋”๋ณด๊ธฐ

ํ•˜์ง€๋งŒ, ์ผ๋ฐ˜์ ์œผ๋กœ Content-Type ์ด text/xml์ด๋‚˜ application/json ์ปจํ…์ธ  ํƒ€์ž…์ธ ๊ฒฝ์šฐ๊ฐ€ ๊ต‰์žฅํžˆ ๋งŽ์œผ๋ฉฐ, ์‚ฌ์šฉ์ž ์ธ์ฆ์„ ์œ„ํ•ด์„œ Cookie ํ˜น์€ Autorization ์™€ ๊ฐ™์€ ์ถ”๊ฐ€ ํ—ค๋”๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋‹จ์ˆœ ์š”์ฒญ์˜ ์กฐ๊ฑด์„ ๋งž์ถ”๊ธฐ๋Š” ์‰ฝ์ง€ ์•Š๋‹ค.

 

๋˜ํ•œ ์• ์ดˆ์— ์ € ์กฐ๊ฑด์— ๋ช…์‹œ๋œ ํ—ค๋”๋“ค์€ ์ง„์งœ ๊ธฐ๋ณธ์ ์ธ ํ—ค๋”๋“ค์ด๊ธฐ ๋•Œ๋ฌธ์—, ๋ณต์žกํ•œ ์ƒ์šฉ ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ ์ด ํ—ค๋”๋“ค ์™ธ์— ์ถ”๊ฐ€์ ์ธ ํ—ค๋”๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋Š” ๋“œ๋ฌผ๋ฉฐ ๋‹น์žฅ ์‚ฌ์šฉ์ž ์ธ์ฆ์— ์‚ฌ์šฉ๋˜๋Š” Authorization ํ—ค๋”์กฐ์ฐจ ์œ„์˜ ์กฐ๊ฑด์—๋Š” ํฌํ•จ๋˜์ง€ ์•Š๋Š”๋‹ค.
(= Authorization ํ—ค๋”๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด Simple Request์— ํ•ด๋‹น๋˜์ง€ ์•Š์Œ!)
(= ์ด์™ธ์— ๋‹ค๋ฅธ ์ปค์Šคํ…€ ํ—ค๋”, ๊ถŒํ•œ๊ณผ ๊ด€๋ จ๋œ ํ—ค๋”๊ฐ€ ์žˆ์œผ๋ฉด Simeple Request์— ํ•ด๋‹น๋˜์ง€ ์•Š์Œ! )

 

์ถ”๊ฐ€์ ์œผ๋กœ HTTP ๋ฉ”์†Œ๋“œ๋“ค ์ค‘ GET ์ด ์™ธ์˜ ๋ฉ”์†Œ๋“œ๋‚˜, POST ๋ฉ”์†Œ๋“œ์—์„œ ํŠน์ • MIME Type์€ ์„œ๋ฒ„ ๋ฐ์ดํ„ฐ์— ์‚ฌ์ด๋“œ ์ดํŽ™ํŠธ๋ฅผ ๋ฐœ์ƒ์‹œํ‚ฌ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ธŒ๋ผ์šฐ์ €๋Š” SimpleRequest๊ฐ€ ์•„๋‹Œ  Preflight Request ๋ฐฉ์‹์œผ๋กœ ์š”์ฒญํ•  ์ˆ˜ ์žˆ๋„๋ก ๊ทœ์ œํ•œ๋‹ค.

 

์‚ฌ์‹ค์ƒ ์ด ์กฐ๊ฑด๋“ค์„ ๋ชจ๋‘ ๋งŒ์กฑ์‹œํ‚ค๋Š” ์ƒํ™ฉ์„ ๋งŒ๋‚˜๊ธฐ ์‰ฝ์ง€ ์•Š์•„ Simple Request ๊ฒฝ์šฐ๋Š” ํ”ํžˆ ๋ณด๊ธฐ ์–ด๋ ต๋‹ค.

 

๐Ÿ“ 2. ํ”„๋ฆฌํ”Œ๋ผ์ดํŠธ ์š”์ฒญ (Preflight Requests)

https://www.baeldung.com/cs/cors-preflight-requests

 

์‹ค์ œ ์š”์ฒญ์„ ๋ณด๋‚ด๊ธฐ ์ „์— ์‚ฌ์ „ ์š”์ฒญ์„ ๋ณด๋‚ด์„œ ํ•ด๋‹น ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•œ์ง€ ๋จผ์ € ํ™•์ธํ•˜๋Š” ๋ฐฉ์‹์„ Preflight ๋ฐฉ์‹์ด๋ผ๊ณ  ํ•œ๋‹ค. Preflight๋Š” OPTIONS ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด ์š”์ฒญ๋œ๋‹ค.

 

Preflight ์š”์ฒญ์€ ๋‹จ์ˆœ ์š”์ฒญ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ์š”์ฒญ์— Origin ํ—ค๋”๋ฅผ ์ถ”๊ฐ€ํ•ด์•ผํ•œ๋‹ค. Preflight ์š”์ฒญ์€ ์—ฌ๊ธฐ์— ๋”ํ•˜์—ฌ ์‹ค์ œ ์š”์ฒญ์˜ ๋ฉ”์„œ๋“œ๋ฅผ Access-Control-Request-Method ํ—ค๋”์—, ์‹ค์ œ ์š”์ฒญ์˜ ์ถ”๊ฐ€ ํ—ค๋” ๋ชฉ๋ก์„ Access-Control-Request-Headers ํ—ค๋”์— ๋‹ด์•„ ๋ณด๋‚ด์•ผํ•œ๋‹ค.

 

์‹ค์ œ ์š”์ฒญ ์ด์ „์— '์ด๋Ÿฐ ๋ฉ”์†Œ๋“œ์™€ ํ—ค๋”๋กœ ์š”์ฒญ์„ ๋ณด๋‚ผ ์˜ˆ์ •์ธ๋ฐ, ๋„ˆํฌ ์„œ๋ฒ„ CORS ์ •์ฑ…์—์„œ ํ—ˆ์šฉํ•˜๋Š” ์š”์ฒญ์ด๋‹ˆ?' ๋ผ๊ณ  ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์„œ๋ฒ„์—๊ฒŒ ๋ฏธ๋ฆฌ ๋ฌผ์–ด๋ณด๋Š” ์ ˆ์ฐจ๋ผ๊ณ  ๋ณด๋ฉด ์‰ฝ๋‹ค.

Origin: http://foo.example
Access-Control-Request-Method: POST
Access-Control-Request-Headers: X-PINGOTHER, Content-Type

 

์‘๋‹ต ์—ญ์‹œ ๋‹จ์ˆœ ์š”์ฒญ๊ณผ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ Access-Control-Allow-Origin ํ—ค๋”๊ฐ€ ์ „์†ก๋˜์–ด์•ผ ํ•œ๋‹ค. ์—ฌ๊ธฐ์— ๋”ํ•ด ์„œ๋ฒ„ ์ธก์—์„œ ํ—ˆ์šฉํ•˜๋Š” ๋ฉ”์„œ๋“œ ๋ชฉ๋ก์ด ๋‹ด๊ธด Access-Control-Allow-Methods ํ—ค๋”์™€ ํ—ˆ๊ฐ€ ํ—ค๋” ๋ชฉ๋ก์ด ๋‹ด๊ธด Access-Control-Allow-Headers ํ—ค๋”, ๋งˆ์ง€๋ง‰์œผ๋กœ Preflight์˜ ์บ์‹œ ๊ธฐ๊ฐ„์ธ Access-Control-Max-Age ์„ ๋ณด๋‚ด์ค˜์•ผ ํ•œ๋‹ค.

Access-Control-Allow-Origin: https://foo.example
Access-Control-Allow-Methods: POST, GET, OPTIONS
Access-Control-Allow-Headers: X-PINGOTHER, Content-Type
Access-Control-Max-Age: 86400
๋”๋ณด๊ธฐ

Preflight ์š”์ฒญ ๋•Œ๋ฌธ์— ์‹ค์ œ ์š”์ฒญ์€ ํ•œ๋ฒˆ์ด์ง€๋งŒ ๋‘๋ฒˆ์˜ ์š”์ฒญ์„ ๋ณด๋‚ด์•ผํ•˜๋Š” ์ผ์ด ๋ฐœ์ƒํ•œ๋‹ค. Preflight ์บ์‹œ ๊ธฐ๊ฐ„์„ ๋ณด๋‚ด๋Š” ์ด์œ ๋Š” Preflight๋กœ ๋ฐœ์ƒํ•˜๋Š” ์ด๋Ÿฐ ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ์ค„์ด๊ธฐ ์œ„ํ•จ์ด๋‹ค.

 

โ“ Preflight ์š”์ฒญ์ด ํ•„์š”ํ•œ ์ด์œ ๋Š” ๋ฌด์—‡์ผ๊นŒ?

 

์œ„์—์„œ ์ด์•ผ๊ธฐํ•œ ๊ฒƒ ์ฒ˜๋Ÿผ CORS๋Š” ์„œ๋ฒ„๊ฐ€ ์•„๋‹Œ ๋ธŒ๋ผ์šฐ์ € ๊ตฌํ˜„ ์ŠคํŽ™์— ํฌํ•จ๋œ ์ •์ฑ…์ด๋‹ค. ๋”ฐ๋ผ์„œ ์„œ๋ฒ„๋Š” CORS ์œ„๋ฐ˜ ์—ฌ๋ถ€์™€ ์ƒ๊ด€์—†์ด ์ผ๋‹จ ์š”์ฒญ์ด ๋“ค์–ด์˜ค๋ฉด ์ฒ˜๋ฆฌ๋ฅผ ํ•˜๊ณ  ์‘๋‹ต์„ ๋ณด๋‚ธ๋‹ค. ๊ทธ ์‘๋‹ต์„ ๋ฐ›์€ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์‘๋‹ต ํ—ค๋”๋ฅผ ํ™•์ธํ•˜๊ณ  ์‘๋‹ต์˜ ํŒŒ๊ธฐ ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •ํ•˜๊ฒŒ ๋œ๋‹ค.

 

GET๊ณผ HEAD์™€ ๊ฐ™์€ ์š”์ฒญ์€ ๋‹จ์ˆœ ์กฐํšŒ๋ฅผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์ƒ๊ด€์—†์ง€๋งŒ, POST, PUT, DELETE ์™€ ๊ฐ™์€ ๋ฉ”์„œ๋“œ๋Š” ์„œ๋ฒ„์— ๋ถ€์ž‘์šฉ (Side Effect) ์„ ์•ผ๊ธฐํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋Š” ์‘๋‹ต์ด ์œ ํšจํ•˜์ง€ ์•Š์•„ ํŒŒ๊ธฐํ•œ ๋ธŒ๋ผ์šฐ์ €์˜ ์˜์‚ฌ์™€ ์ƒ๊ด€์—†์ด ๋ฐœ์ƒํ•œ๋‹ค.

 

Preflight๋Š” ์‹ค์ œ ์š”์ฒญ์ด CORS๋ฅผ ์œ„๋ฐ˜ํ•˜์ง€ ์•Š์•˜๋Š”์ง€๋ฅผ ๋ฏธ๋ฆฌ ํ™•์ธํ•˜๊ณ , ๋ถ€์ž‘์šฉ์œผ๋กœ๋ถ€ํ„ฐ ์„œ๋ฒ„๋ฅผ ๋ณดํ˜ธํ•˜๊ธฐ ์œ„ํ•ด ์ „์†กํ•œ๋‹ค. ํ•˜์ง€๋งŒ POST์™€ ๊ฐ™์€ ๊ฒฝ์šฐ ์กฐ๊ฑด๋งŒ ๋งŒ์กฑํ•˜๋ฉด Preflight ์š”์ฒญ ๋Œ€์‹  ๋‹จ์ˆœ ์š”์ฒญ์œผ๋กœ ์ „์†ก๋  ์ˆ˜ ์žˆ์œผ๋ฏ€๋กœ ๋ฐฑ์—”๋“œ์—์„œ๋„ ์ด์— ๋Œ€ํ•œ ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜๋‹ค.

 

Postman์ด CORS๋ฅผ ๋ฐœ์ƒ์‹œํ‚ค์ง€ ์•Š๋Š” ์ด์œ .

๋”๋ณด๊ธฐ

์ฐธ๊ณ ๋กœ Preflight ์š”์ฒญ์€ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ž๋™์œผ๋กœ ์ „์†ก๋˜๋ฏ€๋กœ ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž๊ฐ€ ์ง์ ‘๋ณด๋‚ผ ํ•„์š”๋Š” ์—†๋‹ค.

๊ฐœ๋ฐœ์„ ํ•˜๋ฉด์„œ Postman ์„ ์‚ฌ์šฉํ•˜๋ฉด ์ •์ƒ์ ์œผ๋กœ ์š”์ฒญ์ด ๋˜๋Š”๋ฐ, ์›น๋ธŒ๋ผ์šฐ์ €์—์„œ ํ˜ธ์ถœ ํ•˜๊ธฐ๋งŒ ํ•˜๋ฉด CORS๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ๊ฒฝ์šฐ๋ฅผ ๊ฒช์–ด๋ดค์„ ๊ฒƒ์ด๋‹ค. ๋ธŒ๋ผ์šฐ์ €์™€ ๋‹ค๋ฅด๊ฒŒ Postman ๊ณผ ๊ฐ™์€ API ํ…Œ์ŠคํŒ… ๋„๊ตฌ์—์„œ๋Š” ๊ธฐ๋ณธ์ ์œผ๋กœ Preflight ๋ฅผ ๋ณด๋‚ด์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

CORS ์ •์ฑ… ์œ„๋ฐ˜ ํ™•์ธ Access-Control-Allow-Origin ๊ฐ’์ด ์กด์žฌ ์œ ๋ฌด

๋”๋ณด๊ธฐ

๐Ÿ˜ฌ ์ฃผ์˜ํ•  ์ 

 

์˜ˆ๋น„ ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต์—์„œ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ณ  ์ •์ƒ์ ์œผ๋กœ 200์ด ๋–จ์–ด์กŒ๋Š”๋ฐ, ์ฝ˜์†” ์ฐฝ์—๋Š” ๋นจ๊ฐ›๊ฒŒ ์—๋Ÿฌ๊ฐ€ ํ‘œ์‹œ๋˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋‹ค. ์ด๋Š” CORS ์ •์ฑ… ์œ„๋ฐ˜์œผ๋กœ ์ธํ•œ ์—๋Ÿฌ๋Š” ์˜ˆ๋น„ ์š”์ฒญ์˜ ์„ฑ๊ณต ์—ฌ๋ถ€์™€ ๋ณ„ ์ƒ๊ด€์ด ์—†๋‹ค. ๋ธŒ๋ผ์šฐ์ €๊ฐ€ CORS ์ •์ฑ… ์œ„๋ฐ˜ ์—ฌ๋ถ€๋ฅผ ํŒ๋‹จํ•˜๋Š” ์‹œ์ ์€ ์˜ˆ๋น„ ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต์„ ๋ฐ›์€ ์ดํ›„์ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

 

๋ฌผ๋ก  ์˜ˆ๋น„ ์š”์ฒญ ์ž์ฒด๊ฐ€ ์‹คํŒจํ•ด๋„ ๋˜‘๊ฐ™์ด CORS ์ •์ฑ… ์œ„๋ฐ˜์œผ๋กœ ์ฒ˜๋ฆฌ๋  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ์ค‘์š”ํ•œ ๊ฒƒ์€ ์˜ˆ๋น„ ์š”์ฒญ์˜ ์„ฑ๊ณต/์‹คํŒจ ์—ฌ๋ถ€๊ฐ€ ์•„๋‹ˆ๋ผ ์‘๋‹ต ํ—ค๋”์— ์œ ํšจํ•œ Access-Control-Allow-Origin ๊ฐ’์ด ์กด์žฌํ•˜๋Š”๊ฐ€์ด๋‹ค. ๋งŒ์•ฝ ์˜ˆ๋น„ ์š”์ฒญ์ด ์‹คํŒจํ•ด์„œ 200์ด ์•„๋‹Œ ์ƒํƒœ ์ฝ”๋“œ๊ฐ€ ๋‚ด๋ ค์˜ค๋”๋ผ๋„ ํ—ค๋”์— ์ € ๊ฐ’์ด ์ œ๋Œ€๋กœ ๋“ค์–ด๊ฐ€์žˆ๋‹ค๋ฉด CORS ์ •์ฑ… ์œ„๋ฐ˜์ด ์•„๋‹ˆ๋ผ๋Š” ์˜๋ฏธ์ด๋‹ค.

 

Access-Control-Allow-Origin  ํ—ˆ์šฉ
Access-Control-Allow-Origin  ํ—ˆ์šฉ X

 

→ ์‘๋‹ต ์ƒํƒœ๋Š” 200์ด์ง€๋งŒAccess-Control-Allow-Origin์—์„œ ์ฐจ์ด๊ฐ€ ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธ ๊ฐ€๋Šฅ.

 

→ 'Access-Control-Allow-Origin: *' ์ด ํ—ค๋”๊ฐ€ ์˜๋ฏธํ•˜๋Š” ๊ฒƒ์€ ์–ด๋– ํ•œ Origin ์ด๋“  ํ—ˆ์šฉํ•œ๋‹ค๋Š” ๋œป์ด๋ฉฐ, ํŠน์ • Origin๋งŒ ํ—ˆ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, ์„œ๋ฒ„์—์„œ ์‘๋‹ตํ—ค๋”์— "Access-Control-Allow-Origin: https://foo.example" ๋กœ ๊ฐ’์„ ์„ค์ •ํ•ด ์ฃผ๋ฉด ๋œ๋‹ค.

 

๐Ÿ“ 3. ์ธ์ฆ์ •๋ณด๋ฅผ ํฌํ•จํ•œ ์š”์ฒญ (Credentialed Requests)

 

3๋ฒˆ์งธ ์‹œ๋‚˜๋ฆฌ์˜ค๋Š” ํ—ค๋”์— ์ธ์ฆ๊ณผ ๊ด€๋ จ๋œ ์ •๋ณด(์ฟ ํ‚ค, ํ† ํฐ ๋“ฑ)๋ฅผ ๋‹ด์•„์„œ ๋ณด๋‚ด๋Š” Credential Request (์ธ์ฆ๋œ ์š”์ฒญ)์„ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.
CORS์˜ ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ์‹์ด๋ผ๊ธฐ ๋ณด๋‹ค๋Š” ๋‹ค๋ฅธ ์ถœ์ฒ˜ ๊ฐ„ ํ†ต์‹ ์—์„œ ์ข€ ๋” ๋ณด์•ˆ์„ ๊ฐ•ํ™”ํ•˜๊ณ  ์‹ถ์„ ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.

 

์˜ˆ๋ฅผ ๋“ค์–ด, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ fetch API๋ฅผ ์‚ฌ์šฉํ•˜๊ฑฐ๋‚˜ Axios, Ajax ๋“ฑ์„ ์‚ฌ์šฉํ•  ๋•Œ ์„œ๋ฒ„๋กœ ์ฟ ํ‚ค๋ฅผ ํ•จ๊ป˜ ์ „์†กํ•ด์•ผ ํ•˜๋Š” ๊ฒฝ์šฐ๊ฐ€ ์žˆ๋Š”๋ฐ, ์š”์ฒญ์— ์ฟ ํ‚ค๊ฐ€ ๋‹ด๊ธฐ๊ฒŒ ๋˜๋ฉด Credentialed Request ํ—ˆ์šฉ์ด ๋˜์–ด ์žˆ์–ด์•ผ ํ•œ๋‹ค.

 

์ฆ‰, ์ธ์ฆ๊ณผ ๊ด€๋ จ๋œ ์ •๋ณด๋ฅผ ๋‹ด์„ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ์˜ต์…˜ 'credentials'๋ฅผ ์ค˜์•ผํ•˜๋Š”๋ฐ, ์ด ๋•Œ ์„œ๋ฒ„ ์ชฝ์—์„œ ์‘๋‹ต ํ—ค๋”์— Access-Control-Allow-Credentials: true๋ฅผ ๋ณด๋‚ด์ฃผ์ง€ ์•Š๋Š”๋‹ค๋ฉด ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‘๋‹ต์„ ๋ฐ›๋Š” ๊ฒƒ์„ ๊ฑฐ๋ถ€ํ•˜๊ฒŒ ๋œ๋‹ค.

 

์ด ์˜ต์…˜์—๋Š” ์ด 3๊ฐ€์ง€์˜ ๊ฐ’์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ฐ ๊ฐ’๋“ค์ด ๊ฐ€์ง€๋Š” ์˜๋ฏธ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

  1. same-origin : ๊ฐ™์€ ์ถœ์ฒ˜ ๊ฐ„ ์š”์ฒญ์—๋งŒ ์ธ์ฆ ์ •๋ณด๋ฅผ ๋‹ด์„ ์ˆ˜ ์žˆ๋‹ค.
  2. include : ๋ชจ๋“  ์š”์ฒญ์— ์ธ์ฆ ์ •๋ณด๋ฅผ ๋‹ด์„ ์ˆ˜ ์žˆ๋‹ค.
  3. omit : ๋ชจ๋“  ์š”์ฒญ์— ์ธ์ฆ ์ •๋ณด๋ฅผ ๋‹ด์ง€ ์•Š๋Š”๋‹ค.
fetch("http://example.com/", {
  method: "PUT",
  credentials: "include",
})
๋”๋ณด๊ธฐ

์ฐธ๊ณ ๋กœ XMLHttpRequest ํ˜น์€ Axios ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒฝ์šฐ withCredentials ์˜ต์…˜์„ true ๋กœ ์„ค์ •ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

๋งŒ์•ฝ same-origin์ด๋‚˜ include์™€ ๊ฐ™์€ ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๋ฆฌ์†Œ์Šค ์š”์ฒญ์— ์ธ์ฆ ์ •๋ณด๊ฐ€ ํฌํ•จ๋œ๋‹ค๋ฉด, ์ด์ œ ๋ธŒ๋ผ์šฐ์ €๋Š” ๋‹ค๋ฅธ ์ถœ์ฒ˜์˜ ๋ฆฌ์†Œ์Šค๋ฅผ ์š”์ฒญํ•  ๋•Œ ๋‹จ์ˆœํžˆ Access-Control-Allow-Origin๋งŒ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ ์ข€ ๋” ๋นก๋นกํ•œ ๊ฒ€์‚ฌ ์กฐ๊ฑด์„ ์ถ”๊ฐ€ํ•˜๊ฒŒ ๋œ๋‹ค.

 

์š”์ฒญ์— ์ธ์ฆ ์ •๋ณด๊ฐ€ ๋‹ด๊ฒจ์žˆ๋Š” ์ƒํƒœ์—์„œ ๋‹ค๋ฅธ ์ถœ์ฒ˜์˜ ๋ฆฌ์†Œ์Šค๋ฅผ ์š”์ฒญํ•˜๊ฒŒ ๋˜๋ฉด ๋ธŒ๋ผ์šฐ์ €๋Š” CORS ์ •์ฑ… ์œ„๋ฐ˜ ์—ฌ๋ถ€๋ฅผ ๊ฒ€์‚ฌํ•˜๋Š” ๋ฃฐ์— ๋‹ค์Œ ๋‘ ๊ฐ€์ง€๋ฅผ ์ถ”๊ฐ€ํ•˜๊ฒŒ ๋œ๋‹ค.

  1. Access-Control-Allow-Origin์—๋Š” * (์™€์ผ๋“œ์นด๋“œ)๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์œผ๋ฉฐ, ๋ช…์‹œ์ ์ธ URL์ด์–ด์•ผํ•œ๋‹ค.
    (https://foo.com๊ณผ ๊ฐ™์ด ๊ตฌ์ฒด์ ์ธ origin์„ ์ง€์ •ํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.)
  2. ์‘๋‹ต ํ—ค๋”์—๋Š” ๋ฐ˜๋“œ์‹œ Access-Control-Allow-Credentials: true๊ฐ€ ์กด์žฌํ•ด์•ผํ•œ๋‹ค.

 


๐Ÿ“š ์ถœ์ฒ˜

 

CORS๊ฐ€ ๋Œ€์ฒด ๋ฌด์—‡์ผ๊นŒ? (feat. SOP)

์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•˜๋‹ค๋ณด๋ฉด ๊ฑฐ์˜ ํ•ญ์ƒ CORS ์ด์Šˆ๋ฅผ ๋งˆ์ฃผํ•˜๊ฒŒ ๋œ๋‹ค. ๊ทธ๋•Œ๋งˆ๋‹ค ํ•ญ์ƒ ์ด๋ฆฌ์ €๋ฆฌ ํ—ค๋งค๋ฉฐ ํ•ด๊ฒฐ๋ฐฉ๋ฒ•๋งŒ์„ ์ฐพ์•„ ๋‹ค๋…”๋Š”๋ฐ, ์ด๋ฒˆ ๊ธฐํšŒ์— CORS๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์กฐ๊ธˆ ๊นŠ๊ฒŒ ๊ณต๋ถ€ํ•ด๋ณด์•˜๋‹ค. ์ถœ์ฒ˜

hudi.blog

 

CORS๋ž€ ๋ฌด์—‡์ธ๊ฐ€?

CORS๊ฐ€ ๋ฌด์—‡์ธ์ง€ ์•Œ๊ธฐ ์ „์—, ์ด CORS๊ฐ€ ๋“ฑ์žฅํ•˜๊ฒŒ ๋œ ๋ฐฐ๊ฒฝ์„ ๋จผ์ € ์•Œ์•„๋ณด์ž.SOP๋Š” 2011๋…„ RFC 6454์—์„œ ๋“ฑ์žฅํ•œ ๋ณด์•ˆ ์ •์ฑ…์œผ๋กœ "๊ฐ™์€ ์ถœ์ฒ˜์—์„œ๋งŒ ๋ฆฌ์†Œ์Šค๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋‹ค"๋ผ๋Š” ๊ทœ์น™์„ ๊ฐ€์ง„ ์ •์ฑ…์ด๋‹ค.๊ทธ๋Ÿฌ

velog.io

https://www.baeldung.com/cs/cors-preflight-requests

 

๋Œ“๊ธ€