๋ณธ๋ฌธ์œผ๋กœ ๊ฑด๋„ˆ๋›ฐ๊ธฐ

CORS

๋ฐฐ๊ฒฝ#

ํ”„๋ก ํŠธ์—”๋“œ์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ณด์—ฌ์ฃผ๊ธฐ ์œ„ํ•ด์„œ๋Š” ์—ฌ๋Ÿฌ ์„œ๋ฒ„์˜ ์ž์›์„ ์š”์ฒญ(request)ํ•˜๊ฒŒ๋œ๋‹ค. ( image , css , js , json ... )

2020-11-09-cors-image-0

๊ธฐ๋ณธ์ ์œผ๋กœ ๋ชจ๋“  HTTP ์š”์ฒญ์€ Cross-Site HTTP Request๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค. ์ฆ‰ <img> ํƒœ๊ทธ์˜ src , <link> ํƒœ๊ทธ๋กœ css , <script> ํƒœ๊ทธ๋กœ JavaScript ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋“ฑ์„๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

ํ•˜์ง€๋งŒ <script></script> ๋กœ ๋‘˜๋Ÿฌ์‹ธ์—ฌ ์žˆ๋Š” ์Šคํฌ๋ฆฝํŠธ ๋‚ด์—์„œ ์ƒ์„ฑ๋œ HTTP Request์— ๋Œ€ํ•ด์„œ๋Š” Same Origin Policy๊ฐ€ ์ ์šฉ๋œ๋‹ค.

Origin ์ด๋ž€?#

2020-11-09-cors-image-1

์—ฌ๊ธฐ์„œ origin ์ด๋ž€ (์„œ๋ธŒ)๋„๋ฉ”์ธ, ํ”„๋กœํ† ์ฝœ, ํฌํŠธ๋ฒˆํ˜ธ๊นŒ์ง€ ๋ชจ๋‘ ํ•ฉ์นœ ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค.

(์ฝ˜์†” ์ฐฝ์—์„œ location.origin ์œผ๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค.)

2020-11-09-cors-image-2

์ฆ‰ ๋„๋ฉ”์ธ, ํ”„๋กœํ† ์ฝœ, ํฌํŠธ๋ฒˆํ˜ธ๊นŒ์ง€ ๋ชจ๋‘ ๊ฐ™์•„์•ผ ๋™์ผ ์ถœ์ฒ˜๋กœ ์ธ์ •๋˜๋Š” ๊ฒƒ์ด๋‹ค.

Cross Origin#

๊ทธ๋Ÿฌ๋ฉด ์Šคํฌ๋ฆฝํŠธ ๋‚ด์—์„œ๋Š” ๊ฐ™์€ ์ถœ์ฒ˜์— ์žˆ๋Š” ์ž์›๋งŒ ์š”์ฒญํ•˜๊ณ , ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š”๊ฐ€? ์•„๋‹ˆ๋‹ค. AJAX๊ฐ€ ๋„๋ฆฌ ์‚ฌ์šฉ๋˜๋ฉด์„œ <script> ๋‚ด๋ถ€์—์„œ๋„ Cross-Site HTTP Request๊ฐ€ ๊ฐ€๋Šฅํ•ด์•ผ ํ•œ๋‹ค๋Š” ์š”๊ตฌ๊ฐ€ ๋Š˜์–ด๋‚˜๋ฉด์„œ W3C๋กœ๋ถ€ํ„ฐ CORS(Cross-Origin-Request-Sharing) ๋ผ๋Š” ๊ถŒ๊ณ ์•ˆ์ด ๋‚˜์˜ค๊ฒŒ ๋˜์—ˆ๋‹ค.

๋ธŒ๋ผ์šฐ์ € (Client-Side)#

๋ธŒ๋ผ์šฐ์ €๋Š” ์Šคํฌ๋ฆฝํŠธ ๋‚ด์˜ ๋‹ค๋ฅธ ์ถœ์ฒ˜์— ๋Œ€ํ•œ HTTP Request Header์— Origin ์ด๋ผ๋Š”ํ•„๋“œ๋ฅผ ์ถ”๊ฐ€ํ•ด์„œ ์š”์ฒญ์„ ๋ณด๋‚ธ๋‹ค.

ํฌ๋กฌ ๋„คํŠธ์›Œํฌ ํƒญ์—์„œ Request Header๋ฅผ ์‚ดํŽด๋ณด์ž. (์„œ๋ฒ„ : http://localhost:3000 )

  • Cross Origin

    2020-11-09-cors-image-3

  • Same Origin

    2020-11-09-cors-image-4

  • <script> ํƒœ๊ทธ ์™ธ๋ถ€์˜ request

    2020-11-09-cors-image-5

โ˜ Cross Origin ์š”์ฒญ์—๋งŒ Origin ํ•„๋“œ๊ฐ€ ์ถ”๊ฐ€๋œ ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

์„œ๋ฒ„ ์‚ฌ์ด๋“œ#

์„œ๋ฒ„์—์„œ ๊ต์ฐจ ์ถœ์ฒ˜ ์š”์ฒญ์„ ํ—ˆ์šฉํ•ด์ฃผ๊ธฐ ์œ„ํ•ด์„œ HTTP response์— Access-Control-Allow-* ์˜ต์…˜๋“ค์„ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.

์„œ๋ฒ„๋Š” Access-Control-Allow-Origin ํ—ค๋”๋กœ ์–ด๋Š ์ถœ์ฒ˜๋ฅผ ํ—ˆ์šฉํ•  ๊ฒƒ์ธ์ง€ ๋ช…์‹œํ•  ์ˆ˜์žˆ๋‹ค.

  • express์—์„œ์˜ ์˜ˆ์‹œ

    • ์ „์ฒด ํ—ˆ์šฉ : res.header('Access-Control-Allow-Origin', '*');

    • ํŠน์ • ์ถœ์ฒ˜ ํ—ˆ์šฉ : res.header('Access-Control-Allow-Origin', 'http://example.com');

2020-11-09-cors-image-6

๋˜ํ•œ Access-Control-Allow-Methods ๋กœ ํ—ˆ์šฉํ•  ๋ฉ”์†Œ๋“œ๋“ค์„ ์ง€์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

  • res.header('Access-Control-Allow-Methods', ["POST", "GET", "PUT"]);

Preflighted Requests#

CORS์—๋Š” ๋‘ ๊ฐ€์ง€ ์œ ํ˜•์˜ ์š”์ฒญ์ด ์žˆ๋‹ค. simple request ์™€ preflighted request ๋‹ค.

์ด๋ฆ„์—์„œ ๋“œ๋Ÿฌ๋‚˜๋“ฏ์ด, simple request๋Š” ๊ฐ„๋‹จํ•œ ์š”์ฒญ, preflighted request๋Š” ๋ฏธ๋ฆฌ ๋ณด๋‚ด๋Š” ์š”์ฒญ์ด๋‹ค.

simple request#

simple request๋Š” ๋‹ค์Œ ์กฐ๊ฑด์„ ๋งŒ์กฑํ•ด์•ผ ํ•œ๋‹ค.

  • GET, POST ๋ฉ”์†Œ๋“œ + (HEAD ๋ฉ”์†Œ๋“œ)

  • POST ๋ฐฉ์‹์ผ ๊ฒฝ์šฐ Content-type์ด ์•„๋ž˜ ์…‹ ์ค‘ ํ•˜๋‚˜

    • application/x-www-form-urlencoded

    • multipart/form-data

    • text/plain

  • ์ปค์Šคํ…€ ํ—ค๋”๋ฅผ ์ „์†กํ•˜์ง€ ๋ง์•„์•ผ ํ•œ๋‹ค.

์ž์„ธํ•œ ์กฐ๊ฑด์€ ์•„๋ž˜์˜ ๋ฌธ์„œ๋ฅผ ์ฐธ์กฐํ•œ๋‹ค.

๊ต์ฐจ ์ถœ์ฒ˜ ๋ฆฌ์†Œ์Šค ๊ณต์œ  (CORS)

preflighted request#

2020-11-09-cors-image-7

preflighted request๋Š” ์‹ค์งˆ์  ์š”์ฒญ(actual request)์„ ๋ณด๋‚ด๊ธฐ ์ „์— Access-Control-Request-* ํ—ค๋”๋ฅผ ์‚ฌ์šฉํ•ด ๋ฏธ๋ฆฌ ์š”์ฒญ์„ ๋ณด๋‚ธ๋‹ค.

2020-11-09-cors-image-8

๋ธŒ๋ผ์šฐ์ €๋Š” ์„œ๋ฒ„๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ ์‘๋‹ต์„ ๋ณด๊ณ , ํ—ˆ์šฉ๋˜์—ˆ๋‹ค๋ฉด ์‹ค์งˆ์  ์š”์ฒญ์„ ๋ณด๋‚ด๊ฒŒ ๋œ๋‹ค.

2020-11-09-cors-image-9

๋งŒ์•ฝ preflighted request๊ฐ€ ํ—ˆ์šฉ๋˜์ง€ ์•Š์•˜๋‹ค๋ฉด ๋ธŒ๋ผ์šฐ์ €๋Š” ์‹ค์งˆ์  ์š”์ฒญ์„ ์ „์†กํ•˜์ง€์•Š๊ฒŒ ๋œ๋‹ค.

์ด๋Ÿฌํ•œ ๋ฐฉ๋ฒ•์„ ํ†ตํ•ด ์„œ๋ฒ„๋Š” ํ—ˆ์šฉํ•˜์ง€ ์•Š์€ ์ถœ์ฒ˜๋กœ๋ถ€ํ„ฐ์˜ ์ž์›์— ๋Œ€ํ•œ ์ ‘๊ทผ์ด๋‚˜ ์ˆ˜์ •์„๋ง‰์•„ ๋ณดํ˜ธ๋ฅผ ๋ฐ›๊ฒŒ ๋œ๋‹ค.

์ฐธ๊ณ ์ž๋ฃŒ#

โœ‹๐Ÿผ๐Ÿ”ฅ CS Visualized: CORS

๊ต์ฐจ ์ถœ์ฒ˜ ๋ฆฌ์†Œ์Šค ๊ณต์œ  (CORS)

Cross Origin Resource Sharing - CORS