๐Ÿ‘ฉ‍๐Ÿ’ป/Web

SOP(Same-Origin-Policy), CORS(Cross-Origin-Resource-Sharing)

ํ•œ๋‚˜ 2021. 5. 10. 21:11

์ž์ฃผ ๋งˆ์ฃผ์น˜๋Š” CORS ์˜ค๋ฅ˜

ํ”„๋ก ํŠธ์—”๋“œ ํ”„๋กœ์ ํŠธ๋ฅผ ํ•  ๋•Œ ์ž์ฃผ ๋งˆ์ฃผ์น˜๋Š” ์˜ค๋ฅ˜ ์ค‘ ํ•˜๋‚˜๋กœ CORS๊ฐ€ ์žˆ๋‹ค. ํ† ์ด ํ”„๋กœ์ ํŠธ๋ฅผ ํ•  ๋•Œ API๋ฅผ ๊ฐ€์ ธ๊ฐ€ ์“ธ ๋•Œ๋„ ๋นˆ๋ฒˆํ•˜๊ฒŒ ๋ฐœ์ƒํ–ˆ๊ณ , ํ˜„์—…์—์„œ ๋ฐฑ์—”๋“œ/ํ”„๋ก ํŠธ์—”๋“œ ์„œ๋ฒ„๋ฅผ ๋‹ค๋ฅด๊ฒŒ ๊ตฌ์ถ•ํ•˜๊ณ  ๊ฐœ๋ฐœํ•  ๋•Œ๋„ ๋งˆ์ฐฌ๊ฐ€์ง€์ด๋‹ค. ํ† ์ด ํ”„๋กœ์ ํŠธ๋ฅผ ํ•  ๋•Œ๋Š” ํ•œ ์ค„ ์ฝ”๋“œ๋ฅผ ๋„ฃ์–ด ํ”„๋ก์‹œ๋ฅผ ์šฐํšŒํ•˜๋„๋ก ํ•˜๋ฉฐ API๋ฅผ ์“ฐ๊ฑฐ๋‚˜(a), webpack ์„ค์ • ํŒŒ์ผ์— ๊ฐœ๋ฐœ ์‹œ์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒ proxy ์„ค์ •(b)์„ ํ•ด์ฃผ๊ณค ํ–ˆ๋‹ค. ์ข€ ๋” ํฐ ๊ทœ๋ชจ์˜ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด์„œ๋Š” ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž์—๊ฒŒ CORS ํ•ด๊ฒฐ์„ ์œ„ํ•ด ํ˜‘์กฐ๋ฅผ ์š”์ฒญํ•ด์„œ ํ•ด๊ฒฐํ–ˆ๋‹ค. (์‚ฌ์ „ ์ง€์‹์ด ๋ถ€์กฑํ–ˆ์„ ๋•Œ ํ”„๋ก ํŠธ์—”๋“œ ๋‹จ์—์„œ ์‹ค์ˆ˜์ธ๊ฐ€ ์‹ถ์–ด์„œ ์˜จ๊ฐ– ์ž๋ฃŒ๋ฅผ ์ฐพ์•„๋ณด๋ฉด์„œ ๋ฐฉ๋ฒ•์„ ๊ฐ•๊ตฌํ•ด๋ดค์ง€๋งŒ AWS ์„œ๋ฒ„ ์„ค์ • ํŽ˜์ด์ง€์—์„œ ๋‹จ ํ•œ ๋ฒˆ์˜ ํด๋ฆญ์œผ๋กœ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ์˜€๋‹ค...)

// Case a:
const proxy = 'https://secret-ocean-49799.herokuapp.com/'
const some_api = `${proxy}https://api.example.com`;

fetch(some_api)
    .then(res => {
          return res.json();
        })
    .catch(err => {
          console.log(err)
    })

// Case b:
// webpack.config.js
// ..
devServer: {
      port: 4000,
      open: true,
      proxy: {
        '/': 'http://localhost'
      }
},
// ..

CORS๊ฐ€ ํ•„์š”ํ•œ ์ด์œ 

์ฒ˜์Œ์—๋Š” CORS ์˜ค๋ฅ˜๊ฐ€ ๊ต‰์žฅํžˆ ๊ท€์ฐฎ๊ณ  ๊นŒ๋‹ค๋กœ์› ๋Š”๋ฐ, CORS๊ฐ€ ์™œ ์‹œ์ž‘๋˜์—ˆ๋Š”์ง€๋ฅผ ์ƒ๊ฐํ•˜๋ฉด, ๋งˆ๋ƒฅ ๊ท€์ฐฎ์•„ํ•  ๋งŒํ•œ ๋ฌธ์ œ๋Š” ์•„๋‹ˆ์—ˆ๋‹ค. CORS๋Š” Cross-Origin-Resource-Sharing์˜ ์ค„์ž„๋ง๋กœ SOP(Same-origin-policy)๋ฅผ ์˜ˆ์™ธ์ ์œผ๋กœ ํ—ˆ์šฉํ•˜๊ธฐ ์œ„ํ•ด ์ƒ๊ฒจ๋‚œ ์ •์ฑ…์ด๋‹ค. ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๊ฐ€ ๋ธŒ๋ผ์šฐ์ €์— ๋„์ž…๋˜๋ฉด์„œ ๋™์ ์ด๊ณ , ํ˜์‹ ์ ์ธ ์ผ์ด ๊ฐ€๋Šฅํ•ด์กŒ์ง€๋งŒ, ๊ทธ๋งŒํผ ๋ณด์•ˆ์ƒ ์œ„ํ—˜๋„๊ฐ€ ์˜ฌ๋ผ๊ฐ„ ํ„ฐ๋ผ ๊ทธ ์ฆˆ์Œ๋ถ€ํ„ฐ ๊ฐ™์€ ์ถœ์ฒ˜์˜ ๋ฆฌ์†Œ์Šคํ•˜๊ณ ๋งŒ ์ƒํ˜ธ์ž‘์šฉํ•œ๋‹ค๋Š” ๋ฃฐ์ด ์ถ”๊ฐ€๋˜์—ˆ๋‹ค.

ํ•˜์ง€๋งŒ, ์œ„์— ์–ธ๊ธ‰ํ•œ ๊ฒƒ์ฒ˜๋Ÿผ ์„œ๋ฒ„๋ฅผ ๋‹ค๋ฅด๊ฒŒ ๊ตฌ์ถ•ํ•˜๊ณ  ๊ฐœ๋ฐœํ•˜๊ธฐ๋„ ํ•˜๋Š” ๋“ฑ ๊ฐ™์€ ์ถœ์ฒ˜(Resource)๊ฐ€ ์•„๋‹Œ ๊ฒฝ์šฐ์— ์†Œํ†ตํ•ด์•ผ ํ•  ์ผ์ด ์ƒ๊ฒผ๋‹ค. ์ด๋ฅผ ์œ„ํ•œ ์ •์ฑ…์ด CORS์ด๋‹ค. ์ด๋•Œ '์ถœ์ฒ˜'๋ž€ ํ”„๋กœํ† ์ฝœ, ํ˜ธ์ŠคํŠธ, ํฌํŠธ๊ฐ€ ๊ฐ™์€ ๊ฒฝ์šฐ๋ฅผ ๊ฐ™์€ ์ถœ์ฒ˜๋ผ ๋งํ•œ๋‹ค. cross-origin์„ ๋‹ค๋ฅธ ์ถœ์ฒ˜๋กœ ์ดํ•ดํ•˜๋ฉด ์ข‹๋‹ค.

CORS Requests

์›น ๋ธŒ๋ผ์šฐ์ € ์œ„์—์„œ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋‹ค๋ฅธ ์ถœ์ฒ˜์˜ ์ž์›์„ ์š”์ฒญํ•  ๋•Œ ์šฐ๋ฆฌ๋Š” ์ด๋ฅผ cross origin requests๋ผ ๋ถ€๋ฅด๋ฉฐ, CORS Preflighted Requests ๊ทธ๋ฆฌ๊ณ  simple requests ์ด๋ ‡๊ฒŒ ํฌ๊ฒŒ ๋‘ ๊ฐ€์ง€ ์ข…๋ฅ˜๋กœ ๋‚˜๋ˆ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

CORS Preflighted Requests

pre ๋ผ๋Š” ์ ‘๋‘์–ด๊ฐ€ ์˜๋ฏธํ•˜๋Š” ๊ฒƒ์ฒ˜๋Ÿผ, ๋ฏธ๋ฆฌ ์š”์ฒญ์„ ๋ณด๋‚ด ์•ž์œผ๋กœ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์„œ๋ฒ„์— HTTP ์š”์ฒญ์„ ์˜ˆ์ •์ธ๋ฐ ์ด๊ฒƒ์ด ๊ฐ€๋Šฅํ•œ์ง€ ๊ฒ€ํ† ํ•˜๋Š” ์š”์ฒญ์ด๋‹ค. OPTION ๋ฉ”์„œ๋“œ๋ฅผ ํ†ตํ•ด ๋ณด๋‚ธ๋‹ค.

Simple Requests

๋ฐ˜๋ฉด ๋‹จ์ˆœ ์š”์ฒญ์€ preflighted request๋ฅผ ์ƒ๋žตํ•œ๋‹ค. ๋Œ€์‹  ํŠน์ • HTTP Method, ํŠน์ • HTTP Header๋ฅผ ๊ฐ–์ถ”๊ณ  ์žˆ์„ ๋•Œ๋งŒ ๊ฐ€๋Šฅํ•œ ์š”์ฒญ์ด๋‹ค.

https://foo.example์˜ ์›น ํŽ˜์ด์ง€์—์„œ https://bar.other ์ถœ์ฒ˜์˜ ๋ฆฌ์†Œ์Šค๋ฅผ ์š”์ฒญํ•˜๊ณ ์ž ํ•  ๋•Œ๋ฅผ ์‚ดํŽด๋ณด์ž. ์•„๋ž˜ ๊ฐ™์€ ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ์ƒ๊ฐํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค.

const xhr = new XMLHttpRequest();
const url = 'https://bar.other/resources/public-data/';

xhr.open('GET', url);
xhr.onreadystatechange = someHandler;
xhr.send();

ํด๋ผ์ด์–ธํŠธ์—์„œ ํ•„์š”ํ•œ ์ž์›์„ ๊ฐ€์ง„ ์„œ๋ฒ„์˜ ์ฃผ์†Œ(https://bar.other/resources/public-data/)๋ฅผ ์š”์ฒญํ•  ๋•Œ(c), ์„œ๋ฒ„๋Š” ์•„๋ž˜์ฒ˜๋Ÿผ CORS ํ—ค๋”๋ฅผ ํ†ตํ•ด ์‘๋‹ตํ•  ๊ฒƒ์ด๋‹ค.(d)

// Case C :
GET /resources/public-data/ HTTP/1.1
Host: bar.other
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:71.0) Gecko/20100101 Firefox/71.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-us,en;q=0.5
Accept-Encoding: gzip,deflate
Connection: keep-alive
Origin: https://foo.example

// Case D:
HTTP/1.1 200 OK
Date: Mon, 01 Dec 2008 00:23:53 GMT
Server: Apache/2
Access-Control-Allow-Origin: *
Keep-Alive: timeout=2, max=100
Connection: Keep-Alive
Transfer-Encoding: chunked
Content-Type: application/xml

[โ€ฆXML Dataโ€ฆ]

์ด๋ ‡๊ฒŒ ์„œ๋ฒ„๊ฐ€ ์‘๋‹ตํ•˜๋ฉด์„œ Access-Control-Allow-Origin ํ—ค๋”๋ฅผ ๋ณด๋‚ด์ฃผ๊ณ  ์žˆ๋Š”๋ฐ, ๊ฐ’์ด * ์™€์ผ๋“œ ์นด๋“œ๋กœ ๋˜์–ด ์žˆ๋‹ค. ๋ฆฌ์†Œ์Šค๋Š” ์–ด๋–ค origin์—์„œ๋“  ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ํ‘œ์‹์ด๋‹ค. ํŽธํ•˜์ง€๋งŒ, ๋ชจ๋“  ๋„๋ฉ”์ธ์—์„œ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๋‹ค๋Š” ๋œป์ด๋ฏ€๋กœ, ๋ณด์•ˆ ์ƒ ์ทจ์•ฝํ•˜๋‹ค.

๋ณด์•ˆ์„ ์กฐ๊ธˆ ๋” ๊ฐ•ํ™”ํ•˜๋ฉด ์•„๋ž˜์ฒ˜๋Ÿผ ์ž‘์„ฑํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

Access-Control-Allow-Origin: https://foo.example

์ด์ œ ์œ„ ๋ฆฌ์†Œ์Šค๋กœ๋ถ€ํ„ฐ ์˜ค๋Š” ์š”์ฒญ๋งŒ ํ—ˆ์šฉํ•œ๋‹ค๋Š” ์˜๋ฏธ์ด๋‹ค.

Reference