CORS๋Š” ์™œ ์ด๋ ‡๊ฒŒ ์šฐ๋ฆฌ๋ฅผ ํž˜๋“ค๊ฒŒ ํ•˜๋Š”๊ฑธ๊นŒ?

    CORS๋Š” ์™œ ์ด๋ ‡๊ฒŒ ์šฐ๋ฆฌ๋ฅผ ํž˜๋“ค๊ฒŒ ํ•˜๋Š”๊ฑธ๊นŒ?


    ์ด๋ฒˆ ํฌ์ŠคํŒ…์—์„œ๋Š” ์›น ๊ฐœ๋ฐœ์ž๋ผ๋ฉด ํ•œ๋ฒˆ์ฏค์€ ์–ป์–ด๋งž์•„ ๋ดค์„ ๋ฒ•ํ•œ CORS(Cross-Origin Resource Sharing) ์ •์ฑ…์— ๋Œ€ํ•œ ์ด์•ผ๊ธฐ๋ฅผ ํ•ด๋ณด๋ ค๊ณ  ํ•œ๋‹ค. ์‚ฌ์‹ค ์›น ๊ฐœ๋ฐœ์„ ํ•˜๋‹ค๋ณด๋ฉด CORS ์ •์ฑ… ์œ„๋ฐ˜์œผ๋กœ ์ธํ•ด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜๋Š” ์ƒํ™ฉ์€ ๊ต‰์žฅํžˆ ํ”ํ•ด์„œ ๋ˆ„๊ตฌ๋‚˜ ํ•œ ๋ฒˆ ์ •๋„๋Š” ๊ฒช๊ฒŒ ๋œ๋‹ค๊ณ  ํ•ด๋„ ๊ณผ์–ธ์ด ์•„๋‹ˆ๋‹ค.

    ํ•„์ž๋Š” ๋Œ€ํ•™์ƒ ๋•Œ ์นœ๊ตฌ๋“ค๊ณผ ํ† ์ด ํ”„๋กœ์ ํŠธ๋ฅผ ๋งŒ๋“ค๋˜ ๊ณผ์ •์— ์ด ์ด์Šˆ๋ฅผ ์ฒ˜์Œ ๊ฒช์—ˆ์—ˆ๋‹ค. ๋‹น์‹œ ํ•„์ž๋Š” ๋กœ์ปฌ ํ™˜๊ฒฝ์—์„œ ํด๋ผ์ด์–ธํŠธ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋งŒ๋“ค๊ณ  ์žˆ์—ˆ๊ณ , ์นœ๊ตฌ๊ฐ€ ๋ฏธ๋ฆฌ ๋งŒ๋“ค์–ด์„œ ๋ฐฐํฌํ•ด๋†“์€ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ API ์„œ๋ฒ„์™€ ํ†ต์‹ ์„ ์‹œ๋„ํ–ˆ์—ˆ๋‹ค.

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

    ๐Ÿšจ Access to fetch at โ€˜https://api.lubycon.com/meโ€™ from origin โ€˜http://localhost:3000โ€™ has been blocked by CORS policy: No โ€˜Access-Control-Allow-Originโ€™ header is present on the requested resource. If an opaque response serves your needs, set the requestโ€™s mode to โ€˜no-corsโ€™ to fetch the resource with CORS disabled.

    what CO...뭐요...? Access 어쩌고를 헤더에 넣으라고...?

    ์ง€๊ธˆ ๋ณด๋ฉด ๋‚˜๋ฆ„ ์นœ์ ˆํ•˜๊ฒŒ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์„ ์ž˜ ์•Œ๋ ค์ฃผ๊ณ  ์žˆ๋Š” ์—๋Ÿฌ ๋ฉ”์„ธ์ง€์ด์ง€๋งŒ, ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ ๊ฒฝํ—˜์ด ์ „๋ฌดํ•˜๋˜ ๋‹น์‹œ ํ•„์ž๋Š” ์ด ๋ฉ”์„ธ์ง€๋ฅผ ๋ณด๊ณ ๋„ ๋ญ˜ ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ•˜๋Š”์ง€ ํ•œ์ฐธ ํ—ค๋งธ๋˜ ๊ธฐ์–ต์ด ๋‚œ๋‹ค.

    CORS์— ๋Œ€ํ•œ ๊ธฐ๋ณธ์ ์ธ ๋‚ด์šฉ

    ์ด๋ ‡๋“ฏ ์šฐ๋ฆฌ๊ฐ€ ๊ฒช๋Š” CORS ๊ด€๋ จ ์ด์Šˆ๋Š” ๋ชจ๋‘ CORS ์ •์ฑ…์„ ์œ„๋ฐ˜ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ๋ฐœ์ƒํ•˜๋Š” ๊ฒƒ์ด๋‹ค. ๊ฐœ๋ฐœํ•˜๋Š” ์ž…์žฅ์—์„œ๋Š” ์ € ์ •์ฑ… ๋•Œ๋ฌธ์— ์‹ ๊ฒฝ์จ์•ผ ํ•˜๋Š” ๊ฒƒ๋“ค์ด ๋Š˜์–ด๋‚˜๋‹ˆ ๊ท€์ฐฎ์„ ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ์‚ฌ์‹ค CORS๋ผ๋Š” ๋ฐฉ์–ด๋ง‰์ด ์กด์žฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์šฐ๋ฆฌ๊ฐ€ ์ด ๊ณณ ์ € ๊ณณ์—์„œ ๊ฐ€์ ธ์˜ค๋Š” ๋ฆฌ์†Œ์Šค๊ฐ€ ์•ˆ์ „ํ•˜๋‹ค๋Š” ์ตœ์†Œํ•œ์˜ ๋ณด์žฅ์„ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

    CORS๋Š” Cross-Origin Resource Sharing์˜ ์ค„์ž„๋ง๋กœ, ํ•œ๊ตญ์–ด๋กœ ์ง์—ญํ•˜๋ฉด ๊ต์ฐจ ์ถœ์ฒ˜ ๋ฆฌ์†Œ์Šค ๊ณต์œ ๋ผ๊ณ  ํ•ด์„ํ•  ์ˆ˜ ์žˆ๋‹ค. ์—ฌ๊ธฐ์„œ โ€œ๊ต์ฐจ ์ถœ์ฒ˜โ€๋ผ๊ณ  ํ•˜๋Š” ๊ฒƒ์€ โ€œ๋‹ค๋ฅธ ์ถœ์ฒ˜โ€๋ฅผ ์˜๋ฏธํ•˜๋Š” ๊ฒƒ์ธ๋ฐ, ์•„๋ฌด๋ž˜๋„ Cross๋ผ๋Š” ์˜๋‹จ์–ด๊ฐ€ ๊ฐ€์ง€๋Š” ๋‰˜์•™์Šค๊ฐ€ ํ•œ๊ตญ์–ด์™€ ์กฐ๊ธˆ์€ ๋‹ค๋ฅด๋‹ค๋ณด๋‹ˆ CORS๋ฅผ ๊ทธ๋Œ€๋กœ ์ง์—ญํ•œ ๊ต์ฐจ ์ถœ์ฒ˜ ๋ฆฌ์†Œ์Šค ๊ณต์œ ๋ผ๋Š” ๋ง๋งŒ ๋ณด๊ณ ๋Š” ์–ด๋–ค ์˜๋ฏธ์ธ์ง€ ๊ฐ์„ ์žก๊ธฐ๊ฐ€ ์กฐ๊ธˆ์€ ์–ด๋ ค์šด ๊ฒƒ ๊ฐ™๋‹ค.

    ๊ทธ๋ž˜์„œ ํ•„์ž๋Š” ์กฐ๊ธˆ ๋” ์‰ฌ์šด ์ดํ•ด๋ฅผ ์œ„ํ•ด ๊ต์ฐจ ์ถœ์ฒ˜๋ผ๋Š” ๋ง ๋Œ€์‹  โ€œ๋‹ค๋ฅธ ์ถœ์ฒ˜โ€๋ผ๋Š” ๋‹จ์–ด๋ฅผ ์‚ฌ์šฉํ•ด์„œ ์ด ํฌ์ŠคํŒ…์„ ํ’€์–ด๋‚˜๊ฐˆ๊นŒ ํ•œ๋‹ค.

    ์ผ๋‹จ ๋‹ค๋ฅธ ์ถœ์ฒ˜๊ฐ„์˜ ๋ฆฌ์†Œ์Šค ๊ณต์œ ์— ๋Œ€ํ•ด์„œ ์•Œ์•„๋ณด๊ธฐ์— ์•ž์„œ ๊ฐ„๋‹จํ•˜๊ฒŒ ์ด ์ถœ์ฒ˜(Origin)๋ผ๋Š” ๊ฒƒ์ด ์ •ํ™•ํžˆ ๋ญ˜ ์˜๋ฏธํ•˜๋Š”์ง€๋ถ€ํ„ฐ ํ•œ๋ฒˆ ์งš๊ณ  ๋„˜์–ด๊ฐ€๋„๋ก ํ•˜์ž.

    ์ถœ์ฒ˜(Origin)๊ฐ€ ๋ฌด์—‡์ธ๊ฐ€์š”?

    ์„œ๋ฒ„์˜ ์œ„์น˜๋ฅผ ์˜๋ฏธํ•˜๋Š” https://google.com๊ณผ ๊ฐ™์€ URL๋“ค์€ ๋งˆ์น˜ ํ•˜๋‚˜์˜ ๋ฌธ์ž์—ด ๊ฐ™์•„ ๋ณด์—ฌ๋„, ์‚ฌ์‹ค์€ ์—ฌ๋Ÿฌ ๊ฐœ์˜ ๊ตฌ์„ฑ ์š”์†Œ๋กœ ์ด๋ฃจ์–ด์ ธ์žˆ๋‹ค.

    uri structure

    ์ด๋•Œ ์ถœ์ฒ˜๋Š” Protocol๊ณผ Host, ๊ทธ๋ฆฌ๊ณ  ์œ„ ๊ทธ๋ฆผ์—๋Š” ๋‚˜์™€์žˆ์ง€ ์•Š์ง€๋งŒ :80, :443๊ณผ ๊ฐ™์€ ํฌํŠธ ๋ฒˆํ˜ธ๊นŒ์ง€ ๋ชจ๋‘ ํ•ฉ์นœ ๊ฒƒ์„ ์˜๋ฏธํ•œ๋‹ค. ์ฆ‰, ์„œ๋ฒ„์˜ ์œ„์น˜๋ฅผ ์ฐพ์•„๊ฐ€๊ธฐ ์œ„ํ•ด ํ•„์š”ํ•œ ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ๊ฒƒ๋“ค์„ ํ•ฉ์ณ๋†“์€ ๊ฒƒ์ด๋‹ค.

    ๋˜ํ•œ ์ถœ์ฒ˜ ๋‚ด์˜ ํฌํŠธ ๋ฒˆํ˜ธ๋Š” ์ƒ๋žต์ด ๊ฐ€๋Šฅํ•œ๋ฐ, ์ด๋Š” ๊ฐ ์›น์—์„œ ์‚ฌ์šฉํ•˜๋Š” HTTP, HTTPS ํ”„๋กœํ† ์ฝœ์˜ ๊ธฐ๋ณธ ํฌํŠธ ๋ฒˆํ˜ธ๊ฐ€ ์ •ํ•ด์ ธ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. HTTP๊ฐ€ ์ •์˜๋œ RFC 2616 ๋ฌธ์„œ๋ฅผ ๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ๊ธฐ๋ณธ ํฌํŠธ ๋ฒˆํ˜ธ๊ฐ€ ํ•จ๊ป˜ ์ •์˜๋˜์–ด์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

    3.3.2 http URL

    โ€ฆ
    If the port is empty or not given, port 80 is assumed. The semantics are that the identified resource is located at the server listening for TCP connections on that port of that host, and the Request-URI for the resource is abs_path (section 5.1.2).
    โ€ฆ

    ๊ทธ๋Ÿฌ๋‚˜ ๋งŒ์•ฝ https://google.com:443๊ณผ ๊ฐ™์ด ์ถœ์ฒ˜์— ํฌํŠธ ๋ฒˆํ˜ธ๊ฐ€ ๋ช…์‹œ์ ์œผ๋กœ ํฌํ•จ๋˜์–ด ์žˆ๋‹ค๋ฉด ์ด ํฌํŠธ ๋ฒˆํ˜ธ๊นŒ์ง€ ๋ชจ๋‘ ์ผ์น˜ํ•ด์•ผ ๊ฐ™์€ ์ถœ์ฒ˜๋ผ๊ณ  ์ธ์ •๋œ๋‹ค. ํ•˜์ง€๋งŒ ์ด ์ผ€์ด์Šค์— ๋Œ€ํ•œ ๋ช…ํ™•ํ•œ ์ •์˜๊ฐ€ ํ‘œ์ค€์œผ๋กœ ์ •ํ•ด์ง„ ๊ฒƒ์€ ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์—, ๋” ์ •ํ™•ํžˆ ์ด์•ผ๊ธฐํ•˜์ž๋ฉด ์–ด๋–ค ๊ฒฝ์šฐ์—๋Š” ๊ฐ™์€ ์ถœ์ฒ˜, ๋˜ ์–ด๋–ค ๊ฒฝ์šฐ์—๋Š” ๋‹ค๋ฅธ ์ถœ์ฒ˜๋กœ ํŒ๋‹จ๋  ์ˆ˜๋„ ์žˆ๋‹ค. (์ง„๋ฆฌ์˜ ์ผ€๋ฐ”์ผ€)

    ์šฐ๋ฆฌ๋Š” ๋ธŒ๋ผ์šฐ์ €์˜ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ์˜ ์ฝ˜์†”์—์„œ Location ๊ฐ์ฒด๊ฐ€ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” origin ํ”„๋กœํผํ‹ฐ์— ์ ‘๊ทผํ•จ์œผ๋กœ์จ ์† ์‰ฝ๊ฒŒ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‹คํ–‰๋˜๊ณ  ์žˆ๋Š” ์ถœ์ฒ˜๋ฅผ ์•Œ์•„๋‚ผ ์ˆ˜๋„ ์žˆ๋‹ค.

    console.log(location.origin);
    "https://evan-moon.github.io"

    SOP(Same-Origin Policy)

    ์›น ์ƒํƒœ๊ณ„์—๋Š” ๋‹ค๋ฅธ ์ถœ์ฒ˜๋กœ์˜ ๋ฆฌ์†Œ์Šค ์š”์ฒญ์„ ์ œํ•œํ•˜๋Š” ๊ฒƒ๊ณผ ๊ด€๋ จ๋œ ๋‘ ๊ฐ€์ง€ ์ •์ฑ…์ด ์กด์žฌํ•œ๋‹ค. ํ•œ ๊ฐ€์ง€๋Š” ์ด ํฌ์ŠคํŒ…์˜ ์ฃผ์ œ์ธ CORS, ๊ทธ๋ฆฌ๊ณ  ๋˜ ํ•œ ๊ฐ€์ง€๋Š” SOP(Same-Origin Policy)์ด๋‹ค.

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

    ๊ทธ๋Ÿฌ๋‚˜ ์›น์ด๋ผ๋Š” ์˜คํ”ˆ์ŠคํŽ˜์ด์Šค ํ™˜๊ฒฝ์—์„œ ๋‹ค๋ฅธ ์ถœ์ฒ˜์— ์žˆ๋Š” ๋ฆฌ์†Œ์Šค๋ฅผ ๊ฐ€์ ธ์™€์„œ ์‚ฌ์šฉํ•˜๋Š” ์ผ์€ ๊ต‰์žฅํžˆ ํ”ํ•œ ์ผ์ด๋ผ ๋ฌด์ž‘์ • ๋ง‰์„ ์ˆ˜๋„ ์—†๋Š” ๋…ธ๋ฆ‡์ด๋‹ˆ ๋ช‡ ๊ฐ€์ง€ ์˜ˆ์™ธ ์กฐํ•ญ์„ ๋‘๊ณ  ์ด ์กฐํ•ญ์— ํ•ด๋‹นํ•˜๋Š” ๋ฆฌ์†Œ์Šค ์š”์ฒญ์€ ์ถœ์ฒ˜๊ฐ€ ๋‹ค๋ฅด๋”๋ผ๋„ ํ—ˆ์šฉํ•˜๊ธฐ๋กœ ํ–ˆ๋Š”๋ฐ, ๊ทธ ์ค‘ ํ•˜๋‚˜๊ฐ€ โ€œCORS ์ •์ฑ…์„ ์ง€ํ‚จ ๋ฆฌ์†Œ์Šค ์š”์ฒญโ€์ด๋‹ค. (์ฐธ๊ณ ๋กœ CORS๋ผ๋Š” ์ด๋ฆ„์ด ์ฒ˜์Œ ๋“ฑ์žฅํ•œ ๊ฒƒ์€ 2009๋…„์ด๋ผ, SOP์˜ ๋“ฑ์žฅ๋ณด๋‹ค ๋น ๋ฅด๋‹ค)

    Access to network resources varies depending on whether the resources are in the same origin as the content attempting to access them.

    Generally, reading information from another origin is forbidden. However, an origin is permitted to use some kinds of resources retrieved from other origins. For example, an origin is permitted to execute script, render images, and apply style sheets from any origin. Likewise, an origin can display content from another origin, such as an HTML document in an HTML frame. Network resources can also opt into letting other origins read their information, for example, using Cross-Origin Resource Sharing.

    RFC 6454 - 3.4.2 Network Access

    ์šฐ๋ฆฌ๊ฐ€ ๋‹ค๋ฅธ ์ถœ์ฒ˜๋กœ ๋ฆฌ์†Œ์Šค๋ฅผ ์š”์ฒญํ•œ๋‹ค๋ฉด SOP ์ •์ฑ…์„ ์œ„๋ฐ˜ํ•œ ๊ฒƒ์ด ๋˜๊ณ , ๊ฑฐ๊ธฐ๋‹ค๊ฐ€ SOP์˜ ์˜ˆ์™ธ ์กฐํ•ญ์ธ CORS ์ •์ฑ…๊นŒ์ง€ ์ง€ํ‚ค์ง€ ์•Š๋Š”๋‹ค๋ฉด ์•„์˜ˆ ๋‹ค๋ฅธ ์ถœ์ฒ˜์˜ ๋ฆฌ์†Œ์Šค๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

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

    ๊ทผ๋ฐ ์™œ ์ด๋ ‡๊ฒŒ ๊ท€์ฐฎ์€ ์ •์ฑ…์„ ๋งŒ๋“ค์–ด์„œ ๊ฐœ๋ฐœ์ž๋“ค์„ ๊ดด๋กญํžˆ๋Š” ๊ฒƒ์ผ๊นŒ? ์–ด์ฐจํ”ผ ๊ฐœ๋ฐœ์ž๋Š” ์ •ํ•ด์ง„ ์„œ๋ฒ„ํ•˜๊ณ ๋งŒ ํ†ต์‹ ์„ ํ•˜๋„๋ก ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์ž‘์„ฑํ•  ํ…๋ฐ ๋ง์ด๋‹ค.

    trust 그냥 개발자를 믿어주시면 안될까요 선생님들...?

    ํ•˜์ง€๋งŒ ์ž˜ ์ƒ๊ฐํ•ด๋ณด๋ฉด ์ด๋ ‡๊ฒŒ ์ถœ์ฒ˜๊ฐ€ ๋‹ค๋ฅธ ๋‘ ๊ฐœ์˜ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋งˆ์Œ๋Œ€๋กœ ์†Œํ†ตํ•  ์ˆ˜ ์žˆ๋Š” ํ™˜๊ฒฝ์€ ๊ฝค ์œ„ํ—˜ํ•œ ํ™˜๊ฒฝ์ด๋‹ค.

    ์• ์ดˆ์— ํด๋ผ์ด์–ธํŠธ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜, ํŠนํžˆ๋‚˜ ์›น์—์„œ ๋Œ์•„๊ฐ€๋Š” ํด๋ผ์ด์–ธํŠธ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์‚ฌ์šฉ์ž์˜ ๊ณต๊ฒฉ์— ๋„ˆ๋ฌด๋‚˜๋„ ์ทจ์•ฝํ•œ ์นœ๊ตฌ๋ผ๋Š” ์‚ฌ์‹ค์„ ์žŠ์ง€๋ง์ž. ๋‹น์žฅ ๋ธŒ๋ผ์šฐ์ €์˜ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ๋งŒ ์—ด์–ด๋„ DOM์ด ์–ด๋–ป๊ฒŒ ์ž‘์„ฑ๋˜์–ด์žˆ๋Š”์ง€, ์–ด๋–ค ์„œ๋ฒ„์™€ ํ†ต์‹ ํ•˜๋Š”์ง€, ๋ฆฌ์†Œ์Šค์˜ ์ถœ์ฒ˜๋Š” ์–ด๋””์ธ์ง€์™€ ๊ฐ™์€ ๊ฐ์ข… ์ •๋ณด๋“ค์„ ์•„๋ฌด๋Ÿฐ ์ œ์žฌ์—†์ด ์—ด๋žŒํ•  ์ˆ˜ ์žˆ์ง€ ์•Š์€๊ฐ€?

    ์ตœ๊ทผ์—๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ๋‚œ๋…ํ™”ํ•ด์„œ ์ฝ๊ธฐ ์–ด๋ ต๋‹ค๊ณ  ํ•˜์ง€๋งŒ, ๋‚œ๋…ํ™”๋Š” ์–ด๋””๊นŒ์ง€๋‚˜ ๋‚œ๋…ํ™”์ผ ๋ฟ์ด์ง€ ์•”ํ˜ธํ™”๊ฐ€ ์•„๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ์•„๋ฌด๋ฆฌ ๋‚œ๋…ํ™”๋˜์–ด์žˆ๋‹ค๊ณ  ํ•ด๋„ ์‚ฌ๋žŒ์ด ๋ฐ”๋กœ ์ดํ•ดํ•  ์ˆ˜ ์—†๋Š” ์ •๋„๋„ ์•„๋‹Œ๋ฐ๋‹ค๊ฐ€, ์†Œ์Šค ์ฝ”๋“œ๋ฅผ ์ง์ ‘ ๋ณผ ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ ์ž์ฒด๊ฐ€ ๋ณด์•ˆ์ ์œผ๋กœ ์ƒ๋‹นํžˆ ์ทจ์•ฝํ•œ ๋ถ€๋ถ„์ด๋‹ค. ์‹ฌ์ง€์–ด ์•„์ง๊นŒ์ง€๋„ ์†Œ์Šค ์ฝ”๋“œ์˜ ๋‚œ๋…ํ™”๊ฐ€ ์•ˆ๋˜์–ด ๊ฐœ๋ฐœ์ž ๋„๊ตฌ๋งŒ ์—ด๋ฉด <script> ํƒœ๊ทธ ์•ˆ์— ๋‚  ๊ฒƒ ๊ทธ๋Œ€๋กœ์˜ ์†Œ์Šค ์ฝ”๋“œ๊ฐ€ ๋–กํ•˜๋‹ˆ ๋…ธ์ถœ๋˜๋Š” ์‚ฌ์ดํŠธ๋“ค๋„ ๋งŽ๋‹ค.

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

    hacker
    5252...이 사이트에 내 스크립트를 심으면 재미있어지겠는걸?

    ์ž, ์ง€๊ธˆ๊นŒ์ง€ ๊ณ„์† ๊ฐ™์€ ์ถœ์ฒ˜, ๋‹ค๋ฅธ ์ถœ์ฒ˜์— ๋Œ€ํ•œ ์ด์•ผ๊ธฐ๋ฅผ ์ค‘์‹ฌ์œผ๋กœ ํฌ์ŠคํŒ…์„ ํ’€์–ด๋‚˜๊ฐ€๊ณ  ์žˆ๋Š”๋ฐ, ๊ทธ๋ ‡๋‹ค๋ฉด ์ •ํ™•ํžˆ ์–ด๋–ค ๊ฒฝ์šฐ์— ์ถœ์ฒ˜๊ฐ€ ๊ฐ™๋‹ค๊ณ  ํŒ๋‹จํ•˜๊ณ , ์–ด๋–ค ๊ฒฝ์šฐ์— ์ถœ์ฒ˜๊ฐ€ ๋‹ค๋ฅด๋‹ค๊ณ  ํŒ๋‹จํ•˜๋Š” ๊ฒƒ์ผ๊นŒ?

    ๊ฐ™์€ ์ถœ์ฒ˜์™€ ๋‹ค๋ฅธ ์ถœ์ฒ˜์˜ ๊ตฌ๋ถ„

    ์‚ฌ์‹ค ๋‘ ๊ฐœ์˜ ์ถœ์ฒ˜๊ฐ€ ์„œ๋กœ ๊ฐ™๋‹ค๊ณ  ํŒ๋‹จํ•˜๋Š” ๋กœ์ง ์ž์ฒด๋Š” ๊ต‰์žฅํžˆ ๊ฐ„๋‹จํ•œ๋ฐ, ๋‘ URL์˜ ๊ตฌ์„ฑ ์š”์†Œ ์ค‘ Scheme, Host, Port, ์ด 3๊ฐ€์ง€๋งŒ ๋™์ผํ•˜๋ฉด ๋œ๋‹ค.

    https://evan-moon.github.io:80๋ผ๋Š” ์ถœ์ฒ˜๋ฅผ ์˜ˆ๋กœ ๋“ค๋ฉด https:// ์ด๋ผ๋Š” ์Šคํ‚ด์— evan-moon.github.io ํ˜ธ์ŠคํŠธ๋ฅผ ๊ฐ€์ง€๊ณ  :80๋ฒˆ ํฌํŠธ๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋‹ค๋Š” ๊ฒƒ๋งŒ ๊ฐ™๋‹ค๋ฉด ๋‚˜๋จธ์ง€๋Š” ์ „๋ถ€ ๋‹ค๋ฅด๋”๋ผ๋„ ๊ฐ™์€ ์ถœ์ฒ˜๋กœ ์ธ์ •์ด ๋œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

    ํ•„์ž์˜ ๋ธ”๋กœ๊ทธ ์ถœ์ฒ˜์ธ https://evan-moon.github.io์™€ ๊ฐ™์€ ์ถœ์ฒ˜๋กœ ์ธ์ •๋˜๋Š” ์˜ˆ์‹œ๋Š” ๋Œ€๋žต ์ด๋Ÿฐ ๋Š๋‚Œ์ด๋‹ค.

    URL ๊ฐ™์€ ์ถœ์ฒ˜ ์ด์œ 
    https://evan-moon.github.io/about O ์Šคํ‚ด, ํ˜ธ์ŠคํŠธ, ํฌํŠธ๊ฐ€ ๋™์ผ
    https://evan-moon.github.io/about?q=์•ˆ๋‡ฝ O ์Šคํ‚ด, ํ˜ธ์ŠคํŠธ, ํฌํŠธ๊ฐ€ ๋™์ผ
    https://user:password@evan-moon.github.io O ์Šคํ‚ด, ํ˜ธ์ŠคํŠธ, ํฌํŠธ๊ฐ€ ๋™์ผ
    http://evan-moon.github.io X ์Šคํ‚ด์ด ๋‹ค๋ฆ„
    https://api.github.io X ํ˜ธ์ŠคํŠธ๊ฐ€ ๋‹ค๋ฆ„
    https://evan-moon.naver.com X ํ˜ธ์ŠคํŠธ๊ฐ€ ๋‹ค๋ฆ„
    https://evan-moon.github.com X ํ˜ธ์ŠคํŠธ๊ฐ€ ๋‹ค๋ฆ„
    https://evan-moon.github.io:8000 ? ๋ธŒ๋ผ์šฐ์ €์˜ ๊ตฌํ˜„์— ๋”ฐ๋ผ ๋‹ค๋ฆ„

    ๋งจ ๋งˆ์ง€๋ง‰์— ์žˆ๋Š” ์ผ€์ด์Šค์˜ ๊ฒฝ์šฐ, ๋งŒ์•ฝ ์ถœ์ฒ˜์— https://evan-moon.github.io:80์ฒ˜๋Ÿผ ํฌํŠธ ๋ฒˆํ˜ธ๊ฐ€ ๋ช…์‹œ๋˜์–ด ์žˆ๋‹ค๋ฉด ๋ช…๋ฐฑํ•˜๊ฒŒ ๋‹ค๋ฅธ ์ถœ์ฒ˜๋กœ ์ธ์ •๋˜๋Š” ๋ถ€๋ถ„์ด์ง€๋งŒ, ์˜ˆ์‹œ๋กœ ๋“  ์ถœ์ฒ˜์˜ ๊ฒฝ์šฐ ํฌํŠธ ๋ฒˆํ˜ธ๊ฐ€ ํฌํ•จ๋˜์ง€ ์•Š์•˜๊ธฐ ๋•Œ๋ฌธ์— ํŒ๋‹จํ•˜๊ธฐ๊ฐ€ ์• ๋งคํ•˜๋‹ค. RFC 6454์˜ Comparing Origins ์„น์…˜์—๋Š” โ€œ๋งŒ์•ฝ ์ถœ์ฒ˜๊ฐ€ ์Šคํ‚ด/ํ˜ธ์ŠคํŠธ/ํฌํŠธ์˜ ์‚ผ์ค‘ ์ฒด๊ณ„๋ผ๋ฉดโ€ฆโ€ ์ด๋ผ๋Š” ์ „์ œ๊ฐ€ ๋ถ™์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์–ด๋–ป๊ฒŒ ํ•ด์„ํ•˜๋ƒ์— ๋”ฐ๋ผ ๊ตฌํ˜„์ด ๋‹ฌ๋ผ์งˆ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

    ๊ทธ๋ž˜์„œ ์ด๋Ÿฐ ๊ฒฝ์šฐ์—๋Š” ๊ฐ ๋ธŒ๋ผ์šฐ์ €๋“ค์˜ ๋…์ž์ ์ธ ์ถœ์ฒ˜ ๋น„๊ต ๋กœ์ง์„ ๋”ฐ๋ผ๊ฐ€๊ฒŒ ๋œ๋‹ค.

    ie is trash
    출처 비교 시 포트 번호를 완전 무시하는 브라우저는 Internet Explorer 밖에 없다.
    그러니 이제 그만 관짝으로 보내주도록 하자
    [출처] memdroid


    ์—ฌ๊ธฐ์„œ ์ค‘์š”ํ•œ ์‚ฌ์‹ค ํ•œ ๊ฐ€์ง€๋Š” ์ด๋ ‡๊ฒŒ ์ถœ์ฒ˜๋ฅผ ๋น„๊ตํ•˜๋Š” ๋กœ์ง์ด ์„œ๋ฒ„์— ๊ตฌํ˜„๋œ ์ŠคํŽ™์ด ์•„๋‹ˆ๋ผ ๋ธŒ๋ผ์šฐ์ €์— ๊ตฌํ˜„๋˜์–ด ์žˆ๋Š” ์ŠคํŽ™์ด๋ผ๋Š” ๊ฒƒ์ด๋‹ค.

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

    cors 서버는 CORS를 위반하더라도 정상적으로 응답을 해주고, 응답의 파기 여부는 브라우저가 결정한다

    ์ฆ‰, CORS๋Š” ๋ธŒ๋ผ์šฐ์ €์˜ ๊ตฌํ˜„ ์ŠคํŽ™์— ํฌํ•จ๋˜๋Š” ์ •์ฑ…์ด๊ธฐ ๋•Œ๋ฌธ์—, ๋ธŒ๋ผ์šฐ์ €๋ฅผ ํ†ตํ•˜์ง€ ์•Š๊ณ  ์„œ๋ฒ„ ๊ฐ„ ํ†ต์‹ ์„ ํ•  ๋•Œ๋Š” ์ด ์ •์ฑ…์ด ์ ์šฉ๋˜์ง€ ์•Š๋Š”๋‹ค. ๋˜ํ•œ CORS ์ •์ฑ…์„ ์œ„๋ฐ˜ํ•˜๋Š” ๋ฆฌ์†Œ์Šค ์š”์ฒญ ๋•Œ๋ฌธ์— ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค๊ณ  ํ•ด๋„ ์„œ๋ฒ„ ์ชฝ ๋กœ๊ทธ์—๋Š” ์ •์ƒ์ ์œผ๋กœ ์‘๋‹ต์„ ํ–ˆ๋‹ค๋Š” ๋กœ๊ทธ๋งŒ ๋‚จ๊ธฐ ๋•Œ๋ฌธ์—, CORS๊ฐ€ ๋Œ์•„๊ฐ€๋Š” ๋ฐฉ์‹์„ ์ •ํ™•ํžˆ ๋ชจ๋ฅด๋ฉด ์—๋Ÿฌ ํŠธ๋ ˆ์ด์‹ฑ์— ๋‚œํ•ญ์„ ๊ฒช์„ ์ˆ˜๋„ ์žˆ๋‹ค.

    CORS๋Š” ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋‚˜์š”?

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

    ๊ธฐ๋ณธ์ ์œผ๋กœ ์›น ํด๋ผ์ด์–ธํŠธ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋‹ค๋ฅธ ์ถœ์ฒ˜์˜ ๋ฆฌ์†Œ์Šค๋ฅผ ์š”์ฒญํ•  ๋•Œ๋Š” HTTP ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•˜์—ฌ ์š”์ฒญ์„ ๋ณด๋‚ด๊ฒŒ ๋˜๋Š”๋ฐ, ์ด๋•Œ ๋ธŒ๋ผ์šฐ์ €๋Š” ์š”์ฒญ ํ—ค๋”์— Origin์ด๋ผ๋Š” ํ•„๋“œ์— ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ์ถœ์ฒ˜๋ฅผ ํ•จ๊ป˜ ๋‹ด์•„๋ณด๋‚ธ๋‹ค.

    Origin: https://evan-moon.github.io

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

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

    Preflight Request

    ํ”„๋ฆฌํ”Œ๋ผ์ดํŠธ(Preflight) ๋ฐฉ์‹์€ ์ผ๋ฐ˜์ ์œผ๋กœ ์šฐ๋ฆฌ๊ฐ€ ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•  ๋•Œ ๊ฐ€์žฅ ๋งˆ์ฃผ์น˜๋Š” ์‹œ๋‚˜๋ฆฌ์˜ค์ด๋‹ค. ์ด ์‹œ๋‚˜๋ฆฌ์˜ค์— ํ•ด๋‹นํ•˜๋Š” ์ƒํ™ฉ์ผ ๋•Œ ๋ธŒ๋ผ์šฐ์ €๋Š” ์š”์ฒญ์„ ํ•œ๋ฒˆ์— ๋ณด๋‚ด์ง€ ์•Š๊ณ  ์˜ˆ๋น„ ์š”์ฒญ๊ณผ ๋ณธ ์š”์ฒญ์œผ๋กœ ๋‚˜๋ˆ„์–ด์„œ ์„œ๋ฒ„๋กœ ์ „์†กํ•œ๋‹ค.

    ์ด๋•Œ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋ณธ ์š”์ฒญ์„ ๋ณด๋‚ด๊ธฐ ์ „์— ๋ณด๋‚ด๋Š” ์˜ˆ๋น„ ์š”์ฒญ์„ Preflight๋ผ๊ณ  ๋ถ€๋ฅด๋Š” ๊ฒƒ์ด๋ฉฐ, ์ด ์˜ˆ๋น„ ์š”์ฒญ์—๋Š” HTTP ๋ฉ”์†Œ๋“œ ์ค‘ OPTIONS ๋ฉ”์†Œ๋“œ๊ฐ€ ์‚ฌ์šฉ๋œ๋‹ค. ์˜ˆ๋น„ ์š”์ฒญ์˜ ์—ญํ• ์€ ๋ณธ ์š”์ฒญ์„ ๋ณด๋‚ด๊ธฐ ์ „์— ๋ธŒ๋ผ์šฐ์ € ์Šค์Šค๋กœ ์ด ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ๊ฒƒ์ด ์•ˆ์ „ํ•œ์ง€ ํ™•์ธํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

    ์ด ๊ณผ์ •์„ ๊ฐ„๋‹จํ•œ ํ”Œ๋กœ์šฐ ์ฐจํŠธ๋กœ ๋‚˜ํƒ€๋‚ด๋ณด๋ฉด ๋Œ€๋žต ์ด๋Ÿฐ ๋Š๋‚Œ์ด๋‹ค.

    cors preflight 브라우저는 본 요청을 보내기 전 예비 요청을 먼저 보내고, 요청의 유효성을 검사한다

    ์šฐ๋ฆฌ๊ฐ€ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์˜ fetch API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ธŒ๋ผ์šฐ์ €์—๊ฒŒ ๋ฆฌ์†Œ์Šค๋ฅผ ๋ฐ›์•„์˜ค๋ผ๋Š” ๋ช…๋ น์„ ๋‚ด๋ฆฌ๋ฉด ๋ธŒ๋ผ์šฐ์ €๋Š” ์„œ๋ฒ„์—๊ฒŒ ์˜ˆ๋น„ ์š”์ฒญ์„ ๋จผ์ € ๋ณด๋‚ด๊ณ , ์„œ๋ฒ„๋Š” ์ด ์˜ˆ๋น„ ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต์œผ๋กœ ํ˜„์žฌ ์ž์‹ ์ด ์–ด๋–ค ๊ฒƒ๋“ค์„ ํ—ˆ์šฉํ•˜๊ณ , ์–ด๋–ค ๊ฒƒ๋“ค์„ ๊ธˆ์ง€ํ•˜๊ณ  ์žˆ๋Š”์ง€์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ์‘๋‹ต ํ—ค๋”์— ๋‹ด์•„์„œ ๋ธŒ๋ผ์šฐ์ €์—๊ฒŒ ๋‹ค์‹œ ๋ณด๋‚ด์ฃผ๊ฒŒ ๋œ๋‹ค.

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

    ์ด ํ”Œ๋กœ์šฐ๋Š” ๋ธŒ๋ผ์šฐ์ €์˜ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ ์ฝ˜์†”์—์„œ๋„ ๊ฐ„๋‹จํ•˜๊ฒŒ ์žฌํ˜„ํ•ด๋ณผ ์ˆ˜ ์žˆ๋Š”๋ฐ, ํ•„์ž์˜ ๋ธ”๋กœ๊ทธ ํ™˜๊ฒฝ์—์„œ ํ•„์ž์˜ ํ‹ฐ์Šคํ† ๋ฆฌ ๋ธ”๋กœ๊ทธ์˜ RSS ํŒŒ์ผ ๋ฆฌ์†Œ์Šค์— ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋ณธ ์š”์ฒญ์„ ๋ณด๋‚ด๊ธฐ ์ „์— OPTIONS ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์˜ˆ๋น„ ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ๊ฒƒ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.

    const headers = new Headers({
      'Content-Type': 'text/xml',
    });
    fetch('https://evanmoon.tistory.com/rss', { headers });
    OPTIONS https://evanmoon.tistory.com/rss
    
    Accept: */*
    Accept-Encoding: gzip, deflate, br
    Accept-Language: en-US,en;q=0.9,ko;q=0.8,ja;q=0.7,la;q=0.6
    Access-Control-Request-Headers: content-type
    Access-Control-Request-Method: GET
    Connection: keep-alive
    Host: evanmoon.tistory.com
    Origin: https://evan-moon.github.io
    Referer: https://evan-moon.github.io/2020/05/21/about-cors/
    Sec-Fetch-Dest: empty
    Sec-Fetch-Mode: cors
    Sec-Fetch-Site: cross-site

    ์‹ค์ œ๋กœ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋ณด๋‚ธ ์š”์ฒญ์„ ๋ณด๋ฉด, ๋‹จ์ˆœํžˆ Origin์— ๋Œ€ํ•œ ์ •๋ณด ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ์ž์‹ ์ด ์˜ˆ๋น„ ์š”์ฒญ ์ดํ›„์— ๋ณด๋‚ผ ๋ณธ ์š”์ฒญ์— ๋Œ€ํ•œ ๋‹ค๋ฅธ ์ •๋ณด๋“ค๋„ ํ•จ๊ป˜ ํฌํ•จ๋˜์–ด ์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

    ์ด ์˜ˆ๋น„ ์š”์ฒญ์—์„œ ๋ธŒ๋ผ์šฐ์ €๋Š” Access-Control-Request-Headers๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž์‹ ์ด ๋ณธ ์š”์ฒญ์—์„œ Content-Type ํ—ค๋”๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์„ ์•Œ๋ ค์ฃผ๊ฑฐ๋‚˜, Access-Control-Request-Method๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ดํ›„ GET ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์„ ์„œ๋ฒ„์—๊ฒŒ ๋ฏธ๋ฆฌ ์•Œ๋ ค์ฃผ๊ณ  ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

    ์ด๋ ‡๊ฒŒ ํ‹ฐ์Šคํ† ๋ฆฌ ์„œ๋ฒ„์— ์˜ˆ๋น„ ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด, ์ด์ œ ํ‹ฐ์Šคํ† ๋ฆฌ ์„œ๋ฒ„๊ฐ€ ์ด ์˜ˆ๋น„ ์š”์ฒญ์— ๋Œ€ํ•œ ์‘๋‹ต์„ ๋ณด๋‚ด์ค€๋‹ค.

    OPTIONS https://evanmoon.tistory.com/rss 200 OK
    
    Access-Control-Allow-Origin: https://evanmoon.tistory.com
    Content-Encoding: gzip
    Content-Length: 699
    Content-Type: text/xml; charset=utf-8
    Date: Sun, 24 May 2020 11:52:33 GMT
    P3P: CP='ALL DSP COR MON LAW OUR LEG DEL'
    Server: Apache
    Vary: Accept-Encoding
    X-UA-Compatible: IE=Edge

    ์—ฌ๊ธฐ์„œ ์šฐ๋ฆฌ๊ฐ€ ๋ˆˆ์—ฌ๊ฒจ ๋ด์•ผํ•  ๊ฒƒ์€ ์„œ๋ฒ„๊ฐ€ ๋ณด๋‚ด์ค€ ์‘๋‹ต ํ—ค๋”์— ํฌํ•จ๋œ Access-Control-Allow-Origin: https://evanmoon.tistory.com๋ผ๋Š” ๊ฐ’์ด๋‹ค.

    ํ‹ฐ์Šคํ† ๋ฆฌ ์„œ๋ฒ„๋Š” ์ด ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•œ ์ถœ์ฒ˜๋Š” ์˜ค์ง https://evanmoon.tistory.com ๋ฟ์ด๋ผ๊ณ  ๋ธŒ๋ผ์šฐ์ €์—๊ฒŒ ์ด์•ผ๊ธฐํ•ด์ค€ ๊ฒƒ์ด๊ณ , ํ•„์ž๊ฐ€ ์ด ์š”์ฒญ์„ ๋ณด๋‚ธ ์ถœ์ฒ˜๋Š” https://evan-moon.github.io์ด๋ฏ€๋กœ ์„œ๋ฒ„๊ฐ€ ํ—ˆ์šฉํ•ด์ค€ ์ถœ์ฒ˜์™€๋Š” ๋‹ค๋ฅธ ์ถœ์ฒ˜์ด๋‹ค.

    ๊ฒฐ๊ตญ ๋ธŒ๋ผ์šฐ์ €๋Š” ์ด ์š”์ฒญ์ด CORS ์ •์ฑ…์„ ์œ„๋ฐ˜ํ–ˆ๋‹ค๊ณ  ํŒ๋‹จํ•˜๊ณ  ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์—๋Ÿฌ๋ฅผ ๋ฑ‰๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

    ๐Ÿšจ Access to fetch at โ€˜https://evanmoon.tistory.com/rssโ€™ from origin โ€˜https://evan-moon.github.ioโ€™ has been blocked by CORS policy: Response to preflight request doesnโ€™t pass access control check: The โ€˜Access-Control-Allow-Originโ€™ header has a value โ€˜http://evanmoon.tistory.comโ€™ that is not equal to the supplied origin. Have the server send the header with a valid value, or, if an opaque response serves your needs, set the requestโ€™s mode to โ€˜no-corsโ€™ to fetch the resource with CORS disabled.

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

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

    ๋Œ€๋ถ€๋ถ„์˜ ๊ฒฝ์šฐ ์ด๋ ‡๊ฒŒ ์˜ˆ๋น„ ์š”์ฒญ, ๋ณธ ์š”์ฒญ์„ ๋‚˜๋ˆ„์–ด ๋ณด๋‚ด๋Š” ํ”„๋ฆฌํ”Œ๋ผ์ดํŠธ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๊ธฐ๋Š” ํ•˜์ง€๋งŒ, ๋ชจ๋“  ์ƒํ™ฉ์—์„œ ์ด๋ ‡๊ฒŒ ๋‘ ๋ฒˆ์”ฉ ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ์กฐ๊ธˆ ๊นŒ๋‹ค๋กœ์šด ์กฐ๊ฑด์ด๊ธฐ๋Š” ํ•˜์ง€๋งŒ ์–ด๋–ค ๊ฒฝ์šฐ์—๋Š” ์˜ˆ๋น„ ์š”์ฒญ์—†์ด ๋ณธ ์š”์ฒญ๋งŒ์œผ๋กœ CORS ์ •์ฑ… ์œ„๋ฐ˜ ์—ฌ๋ถ€๋ฅผ ๊ฒ€์‚ฌํ•˜๊ธฐ๋„ ํ•œ๋‹ค.

    Simple Request

    ์ด ์‹œ๋‚˜๋ฆฌ์˜ค์— ๋Œ€ํ•œ ์ •์‹ ๋ช…์นญ์€ ์—†์ง€๋งŒ MDN์˜ CORS ๋ฌธ์„œ์—์„œ๋Š” ์ด ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ Simple Request๋ผ๊ณ  ๋ถ€๋ฅด๊ณ  ์žˆ์œผ๋‹ˆ, ํ•„์ž๋„ ๊ทธ๋ƒฅ ๋‹จ์ˆœ ์š”์ฒญ(Simple Request)์ด๋ผ๊ณ  ๋ถ€๋ฅด๋„๋ก ํ•˜๊ฒ ๋‹ค.

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

    simple request 단순 요청은 예비 요청없이 바로 본 요청으로 퉁치는 시나리오이다

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


    1. ์š”์ฒญ์˜ ๋ฉ”์†Œ๋“œ๋Š” GET, HEAD, POST ์ค‘ ํ•˜๋‚˜์—ฌ์•ผ ํ•œ๋‹ค.
    2. Accept, Accept-Language, Content-Language, Content-Type, DPR, Downlink, Save-Data, Viewport-Width, Width๋ฅผ ์ œ์™ธํ•œ ํ—ค๋”๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋œ๋‹ค.
    3. ๋งŒ์•ฝ Content-Type๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ์—๋Š” application/x-www-form-urlencoded, multipart/form-data, text/plain๋งŒ ํ—ˆ์šฉ๋œ๋‹ค.

    ์‚ฌ์‹ค 1๋ฒˆ ์กฐ๊ฑด์˜ ๊ฒฝ์šฐ๋Š” ๊ทธ๋ƒฅ PUT์ด๋‚˜ DELETE ๊ฐ™์€ ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์œผ๋ฉด ๋˜๋Š” ๊ฒƒ ๋ฟ์ด๋‹ˆ ๊ทธ๋ ‡๊ฒŒ ๋ณด๊ธฐ ๋“œ๋ฌธ ์ƒํ™ฉ์€ ์•„๋‹ˆ์ง€๋งŒ, 2๋ฒˆ์ด๋‚˜ 3๋ฒˆ ์กฐ๊ฑด ๊ฐ™์€ ๊ฒฝ์šฐ๋Š” ์กฐ๊ธˆ ๊นŒ๋‹ค๋กญ๋‹ค.

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

    ๊ฒŒ๋‹ค๊ฐ€ ๋Œ€๋ถ€๋ถ„์˜ HTTP API๋Š” text/xml์ด๋‚˜ application/json ์ปจํ…์ธ  ํƒ€์ž…์„ ๊ฐ€์ง€๋„๋ก ์„ค๊ณ„๋˜๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์‹ค ์ƒ ์ด ์กฐ๊ฑด๋“ค์„ ๋ชจ๋‘ ๋งŒ์กฑ์‹œํ‚ค๋Š” ์ƒํ™ฉ์„ ๋งŒ๋“ค๊ธฐ๋Š” ๊ทธ๋ ‡๊ฒŒ ์‰ฝ์ง€ ์•Š์€ ๊ฒƒ์ด ํ˜„์‹ค์ด๋‹ค.

    Credentialed Request

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

    ๊ธฐ๋ณธ์ ์œผ๋กœ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ œ๊ณตํ•˜๋Š” ๋น„๋™๊ธฐ ๋ฆฌ์†Œ์Šค ์š”์ฒญ API์ธ XMLHttpRequest ๊ฐ์ฒด๋‚˜ fetch API๋Š” ๋ณ„๋„์˜ ์˜ต์…˜ ์—†์ด ๋ธŒ๋ผ์šฐ์ €์˜ ์ฟ ํ‚ค ์ •๋ณด๋‚˜ ์ธ์ฆ๊ณผ ๊ด€๋ จ๋œ ํ—ค๋”๋ฅผ ํ•จ๋ถ€๋กœ ์š”์ฒญ์— ๋‹ด์ง€ ์•Š๋Š”๋‹ค. ์ด๋•Œ ์š”์ฒญ์— ์ธ์ฆ๊ณผ ๊ด€๋ จ๋œ ์ •๋ณด๋ฅผ ๋‹ด์„ ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ์˜ต์…˜์ด ๋ฐ”๋กœ credentials ์˜ต์…˜์ด๋‹ค.

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

    ์˜ต์…˜ ๊ฐ’ ์„ค๋ช…
    same-origin (๊ธฐ๋ณธ๊ฐ’) ๊ฐ™์€ ์ถœ์ฒ˜ ๊ฐ„ ์š”์ฒญ์—๋งŒ ์ธ์ฆ ์ •๋ณด๋ฅผ ๋‹ด์„ ์ˆ˜ ์žˆ๋‹ค
    include ๋ชจ๋“  ์š”์ฒญ์— ์ธ์ฆ ์ •๋ณด๋ฅผ ๋‹ด์„ ์ˆ˜ ์žˆ๋‹ค
    omit ๋ชจ๋“  ์š”์ฒญ์— ์ธ์ฆ ์ •๋ณด๋ฅผ ๋‹ด์ง€ ์•Š๋Š”๋‹ค

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

    ๋ฐฑ๋ฌธ์ด๋ถˆ์—ฌ์ผ๊ฒฌ์ด๋‹ˆ ํ•„์ž๊ฐ€ ์ง€๊ธˆ ์ด ํฌ์ŠคํŒ…์„ ์ž‘์„ฑํ•˜๊ณ  ์žˆ๋Š” ๋กœ์ปฌ ํ™˜๊ฒฝ๊ณผ ํ•„์ž์˜ ๋ธ”๋กœ๊ทธ๋ฅผ ํ˜ธ์ŠคํŒ…ํ•˜๊ณ  ์žˆ๋Š” Github ์„œ๋ฒ„์™€์˜ ํ†ต์‹ ์„ ํ†ตํ•ด, ์–ด๋–ค ์ œ์•ฝ์ด ์ถ”๊ฐ€๋˜์—ˆ๋Š”์ง€ ์ง์ ‘ ์‚ดํŽด๋ณด๋Š” ๊ฒƒ์ด ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค.

    ํ•„์ž์˜ ๋ธ”๋กœ๊ทธ๋Š” Access-Control-Allow-Origin ๊ฐ’์œผ๋กœ ๋ชจ๋“  ์ถœ์ฒ˜๋ฅผ ํ—ˆ์šฉํ•œ๋‹ค๋Š” ์˜๋ฏธ์ธ *๊ฐ€ ์„ค์ •๋˜์–ด์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ๋‹ค๋ฅธ ์ถœ์ฒ˜์—์„œ ํ•„์ž์˜ ๋ธ”๋กœ๊ทธ๋กœ ๋ฆฌ์†Œ์Šค๋ฅผ ์š”์ฒญํ•  ๋•Œ CORS ์ •์ฑ… ์œ„๋ฐ˜์œผ๋กœ ์ธํ•œ ์ œ์•ฝ์„ ๋ฐ›์ง€ ์•Š๋Š”๋‹ค.

    ๊ทธ๋ž˜์„œ http://localhost:8000๊ณผ ๊ฐ™์€ ๋กœ์ปฌ์˜ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ๋„ fetch API๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋งˆ์Œ๋Œ€๋กœ ๋ฆฌ์†Œ์Šค๋ฅผ ์š”์ฒญํ•˜๊ณ , ๋˜ ๋ฐ›์•„์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

    fetch('https://evan-moon.github.io/feed.xml');
    Request
    GET https://evan-moon.github.io/feed.xml
    
    Origin: http://localhost:8000
    Referer: http://localhost:8000/2020/05/21/about-cors/
    Response
    GET https://evan-moon.github.io/feed.xml 200 OK
    
    Access-Control-Allow-Origin: *
    Content-Encoding: gzip
    Content-Length: 1132748
    Content-Type: application/xml
    Server: GitHub.com
    Status: 200

    ๋˜ํ•œ ๊ตฌ๊ธ€ ํฌ๋กฌ ๋ธŒ๋ผ์šฐ์ €์˜ credentials ๊ธฐ๋ณธ ๊ฐ’์€ ๊ฐ™์€ ์ถœ์ฒ˜ ๋‚ด์—์„œ๋งŒ ์ธ์ฆ ์ •๋ณด๋ฅผ ์‚ฌ์šฉํ•˜๊ฒ ๋‹ค๋Š” same-origin์ด๊ธฐ ๋•Œ๋ฌธ์—, ํ•„์ž์˜ ๋กœ์ปฌ ํ™˜๊ฒฝ์—์„œ https://evan-moon.github.io๋กœ ๋ณด๋‚ด๋Š” ๋ฆฌ์†Œ์Šค ์š”์ฒญ์—๋Š” ๋‹น์—ฐํžˆ ๋ธŒ๋ผ์šฐ์ €์˜ ์ฟ ํ‚ค์™€ ๊ฐ™์€ ์ธ์ฆ ์ •๋ณด๊ฐ€ ํฌํ•จ๋˜์–ด ์žˆ์ง€ ์•Š๋‹ค.

    ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— ๋ธŒ๋ผ์šฐ์ €๋Š” ๋‹จ์ˆœํžˆ Access-Control-Allow-Origin: *์ด๋ผ๋Š” ๊ฐ’๋งŒ ๋ณด๊ณ  โ€œ์ด ์š”์ฒญ์€ ์•ˆ์ „ํ•˜๊ตฌ๋งŒโ€์ด๋ผ๋Š” ๊ฒฐ๋ก ์„ ๋‚ด๋ฆฌ๋Š” ๊ฒƒ์ด๋‹ค. ๊ทธ๋Ÿฌ๋‚˜ ํ•„์ž๊ฐ€ credentials ์˜ต์…˜์„ ๋ชจ๋“  ์š”์ฒญ์— ์ธ์ฆ ์ •๋ณด๋ฅผ ํฌํ•จํ•˜๊ฒ ๋‹ค๋Š” ์˜๋ฏธ๋ฅผ ๊ฐ€์ง„ include๋กœ ๋ณ€๊ฒฝํ•˜๊ณ  ๊ฐ™์€ ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด ์ด๋ฒˆ์—๋Š” ์ƒํ™ฉ์ด ์กฐ๊ธˆ ๋‹ฌ๋ผ์ง„๋‹ค.

    fetch('https://evan-moon.github.io/feed.xml', {
      credentials: 'include', // Credentials ์˜ต์…˜ ๋ณ€๊ฒฝ!
    });

    ์ง์ ‘ ๋ธŒ๋ผ์šฐ์ € ์ฝ˜์†”์—์„œ ์‹คํ–‰ํ•ด๋ณด๋ฉด ์•Œ๊ฒ ์ง€๋งŒ, ์ด๋ฒˆ์—๋Š” credentials: include ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ๋™์ผ ์ถœ์ฒ˜ ์—ฌ๋ถ€์™€ ์ƒ๊ด€์—†์ด ๋ฌด์กฐ๊ฑด ์š”์ฒญ์— ์ธ์ฆ ์ •๋ณด๊ฐ€ ํฌํ•จ๋˜๋„๋ก ์„ค์ •ํ–ˆ์œผ๋ฏ€๋กœ, ์ด๋ฒˆ ์š”์ฒญ์—๋Š” ๋ธŒ๋ผ์šฐ์ €์˜ ์ฟ ํ‚ค ์ •๋ณด๊ฐ€ ํ•จ๊ป˜ ๋‹ด๊ฒจ์žˆ๋Š” ๊ฒƒ์„ ํ™•์ธํ•ด๋ณผ ์ˆ˜ ์žˆ๋‹ค.

    ํ•„์ž์˜ ๋ธ”๋กœ๊ทธ๋ฅผ ํ˜ธ์ŠคํŒ…ํ•˜๊ณ  ์žˆ๋Š” Github ์„œ๋ฒ„๋Š” ์ด๋ฒˆ์—๋„ ๋™์ผํ•œ ์‘๋‹ต์„ ๋ณด๋‚ด์ฃผ์—ˆ์ง€๋งŒ, ๋ธŒ๋ผ์šฐ์ €์˜ ๋ฐ˜์‘์€ ๋‹ค๋ฅด๋‹ค.

    ๐Ÿšจ Access to fetch at โ€™https://evan-moon.github.io/feed.xmlโ€™ from origin โ€™http://localhost:8000โ€™ has been blocked by CORS policy: The value of the โ€˜Access-Control-Allow-Originโ€™ header in the response must not be the wildcard โ€™*โ€™ when the requestโ€™s credentials mode is โ€˜includeโ€™.

    ๋ธŒ๋ผ์šฐ์ €๋Š” ์ธ์ฆ ๋ชจ๋“œ๊ฐ€ include์ผ ๊ฒฝ์šฐ, ๋ชจ๋“  ์š”์ฒญ์„ ํ—ˆ์šฉํ•œ๋‹ค๋Š” ์˜๋ฏธ์˜ *๋ฅผ Access-Control-Allow-Origin ํ—ค๋”์— ์‚ฌ์šฉํ•˜๋ฉด ์•ˆ๋œ๋‹ค๊ณ  ์ด์•ผ๊ธฐํ•˜๊ณ  ์žˆ๋‹ค.

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


    1. Access-Control-Allow-Origin์—๋Š” *๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์œผ๋ฉฐ, ๋ช…์‹œ์ ์ธ URL์ด์–ด์•ผํ•œ๋‹ค.
    2. ์‘๋‹ต ํ—ค๋”์—๋Š” ๋ฐ˜๋“œ์‹œ Access-Control-Allow-Credentials: true๊ฐ€ ์กด์žฌํ•ด์•ผํ•œ๋‹ค.

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

    CORS๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•

    ์ง€๊ธˆ๊นŒ์ง€ CORS๊ฐ€ ๋ฌด์—‡์ธ์ง€, ์–ด๋–ค ์ƒํ™ฉ์—์„œ CORS ์ •์ฑ…์ด ์ ์šฉ๋˜๊ณ  ์œ„๋ฐ˜๋˜๋Š” ๊ฒƒ์ธ์ง€ ์•Œ์•„๋ดค๋‹ค๋ฉด ์ด๋ฒˆ ์„น์…˜์—์„œ๋Š” ์‹ค์งˆ์ ์œผ๋กœ CORS ์ •์ฑ… ์œ„๋ฐ˜์œผ๋กœ ์ธํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ–ˆ์„ ๊ฒฝ์šฐ์— ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด๋„๋ก ํ•˜์ž.

    Access-Control-Allow-Origin ์„ธํŒ…ํ•˜๊ธฐ

    CORS ์ •์ฑ… ์œ„๋ฐ˜์œผ๋กœ ์ธํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๋Š” ๊ฐ€์žฅ ๋Œ€ํ‘œ์ ์ธ ๋ฐฉ๋ฒ•์€, ๊ทธ๋ƒฅ ์ •์„๋Œ€๋กœ ์„œ๋ฒ„์—์„œ Access-Control-Allow-Origin ํ—ค๋”์— ์•Œ๋งž์€ ๊ฐ’์„ ์„ธํŒ…ํ•ด์ฃผ๋Š” ๊ฒƒ์ด๋‹ค.

    ์ด๋•Œ ์™€์ผ๋“œ์นด๋“œ์ธ *์„ ์‚ฌ์šฉํ•˜์—ฌ ์ด ํ—ค๋”๋ฅผ ์„ธํŒ…ํ•˜๊ฒŒ ๋˜๋ฉด ๋ชจ๋“  ์ถœ์ฒ˜์—์„œ ์˜ค๋Š” ์š”์ฒญ์„ ๋ฐ›์•„๋จน๊ฒ ๋‹ค๋Š” ์˜๋ฏธ์ด๋ฏ€๋กœ ๋‹น์žฅ์€ ํŽธํ•  ์ˆ˜ ์žˆ๊ฒ ์ง€๋งŒ, ๋ฐ”๊ฟ”์„œ ์ƒ๊ฐํ•˜๋ฉด ์ •์ฒด๋„ ๋ชจ๋ฅด๋Š” ์ด์ƒํ•œ ์ถœ์ฒ˜์—์„œ ์˜ค๋Š” ์š”์ฒญ๊นŒ์ง€ ๋ชจ๋‘ ๋ฐ›์•„๋จน๊ฒ ๋‹ค๋Š” ์˜คํ”ˆ ๋งˆ์ธ๋“œ์™€ ๋‹ค๋ฅผ ๊ฒƒ ์—†์œผ๋ฏ€๋กœ ๋ณด์•ˆ์ ์œผ๋กœ ์‹ฌ๊ฐํ•œ ์ด์Šˆ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

    ๊ทธ๋Ÿฌ๋‹ˆ ๊ฐ€๊ธ‰์ ์ด๋ฉด ๊ท€์ฐฎ๋”๋ผ๋„ Access-Control-Allow-Origin: https://evan.github.io์™€ ๊ฐ™์ด ์ถœ์ฒ˜๋ฅผ ๋ช…์‹œํ•ด์ฃผ๋„๋ก ํ•˜์ž.

    ์ด ํ—ค๋”๋Š” Nginx๋‚˜ Apache์™€ ๊ฐ™์€ ์„œ๋ฒ„ ์—”์ง„์˜ ์„ค์ •์—์„œ ์ถ”๊ฐ€ํ•  ์ˆ˜๋„ ์žˆ์ง€๋งŒ, ์•„๋ฌด๋ž˜๋„ ๋ณต์žกํ•œ ์„ธํŒ…์„ ํ•˜๊ธฐ๋Š” ๋ถˆํŽธํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์†Œ์Šค ์ฝ”๋“œ ๋‚ด์—์„œ ์‘๋‹ต ๋ฏธ๋“ค์›จ์–ด ๋“ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ์„ธํŒ…ํ•˜๋Š” ๊ฒƒ์„ ์ถ”์ฒœํ•œ๋‹ค. Spring, Express, Django์™€ ๊ฐ™์ด ์ด๋ฆ„์žˆ๋Š” ๋ฐฑ์—”๋“œ ํ”„๋ ˆ์ž„์›Œํฌ์˜ ๊ฒฝ์šฐ์—๋Š” ๋ชจ๋‘ CORS ๊ด€๋ จ ์„ค์ •์„ ์œ„ํ•œ ์„ธํŒ…์ด๋‚˜ ๋ฏธ๋“ค์›จ์–ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์ œ๊ณตํ•˜๊ณ  ์žˆ์œผ๋‹ˆ ์„ธํŒ… ์ž์ฒด๊ฐ€ ์–ด๋ ต์ง€๋Š” ์•Š์„ ๊ฒƒ์ด๋‹ค.

    Webpack Dev Server๋กœ ๋ฆฌ๋ฒ„์Šค ํ”„๋ก์‹ฑํ•˜๊ธฐ

    ์‚ฌ์‹ค CORS๋ฅผ ๊ฐ€์žฅ ๋งŽ์ด ๋งˆ์ฃผ์น˜๋Š” ํ™˜๊ฒฝ์€ ๋ฐ”๋กœ ๋กœ์ปฌ์—์„œ ํ”„๋ก ํŠธ์—”๋“œ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๊ฐœ๋ฐœํ•˜๋Š” ๊ฒฝ์šฐ๋ผ๊ณ  ํ•ด๋„ ๊ณผ์–ธ์ด ์•„๋‹ˆ๋‹ค. ๋ฐฑ์—”๋“œ์—๋Š” ์ด๋ฏธ Access-Control-Allow-Origin ํ—ค๋”๊ฐ€ ์„ธํŒ…๋˜์–ด์žˆ๊ฒ ์ง€๋งŒ, ์ด ์ค‘์š”ํ•œ ํ—ค๋”์—๋‹ค๊ฐ€ http://localhost:3000 ๊ฐ™์€ ๋ฒ”์šฉ์ ์ธ ์ถœ์ฒ˜๋ฅผ ๋„ฃ์–ด์ฃผ๋Š” ๊ฒฝ์šฐ๋Š” ๋“œ๋ฌผ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

    ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž๋Š” ๋Œ€๋ถ€๋ถ„ ์›นํŒฉ๊ณผ webpack-dev-server๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž์‹ ์˜ ๋จธ์‹ ์— ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์„ ๊ตฌ์ถ•ํ•˜๊ฒŒ ๋˜๋Š”๋ฐ, ์ด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ œ๊ณตํ•˜๋Š” ํ”„๋ก์‹œ ๊ธฐ๋Šฅ์„ ์‚ฌ์šฉํ•˜๋ฉด ์•„์ฃผ ํŽธํ•˜๊ฒŒ CORS ์ •์ฑ…์„ ์šฐํšŒํ•  ์ˆ˜ ์žˆ๋‹ค.

    module.exports = {
      devServer: {
        proxy: {
          '/api': {
            target: 'https://api.evan.com',
            changeOrigin: true,
            pathRewrite: { '^/api': '' },
          },
        }
      }
    }

    ์ด๋ ‡๊ฒŒ ์„ค์ •์„ ํ•ด๋†“์œผ๋ฉด ๋กœ์ปฌ ํ™˜๊ฒฝ์—์„œ /api๋กœ ์‹œ์ž‘ํ•˜๋Š” URL๋กœ ๋ณด๋‚ด๋Š” ์š”์ฒญ์— ๋Œ€ํ•ด ๋ธŒ๋ผ์šฐ์ €๋Š” localhost:8000/api๋กœ ์š”์ฒญ์„ ๋ณด๋‚ธ ๊ฒƒ์œผ๋กœ ์•Œ๊ณ  ์žˆ์ง€๋งŒ, ์‚ฌ์‹ค ๋’ค์—์„œ ์›นํŒฉ์ด https://api.evan.com์œผ๋กœ ์š”์ฒญ์„ ํ”„๋ก์‹ฑํ•ด์ฃผ๊ธฐ ๋•Œ๋ฌธ์— ๋งˆ์น˜ CORS ์ •์ฑ…์„ ์ง€ํ‚จ ๊ฒƒ์ฒ˜๋Ÿผ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ์†์ด๋ฉด์„œ๋„ ์šฐ๋ฆฌ๋Š” ์›ํ•˜๋Š” ์„œ๋ฒ„์™€ ์ž์œ ๋กญ๊ฒŒ ํ†ต์‹ ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฆ‰, ํ”„๋ก์‹ฑ์„ ํ†ตํ•ด CORS ์ •์ฑ…์„ ์šฐํšŒํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

    trap 웹팩의 함정 카드 리버스 프록싱(이)가 발동했다!

    ํ˜น์‹œ webpack-dev-middleware์™€ Node ์„œ๋ฒ„์˜ ์กฐํ•ฉ์œผ๋กœ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์„ ์ง์ ‘ ๊ตฌ์ถ•ํ–ˆ๋”๋ผ๋„ http-proxy-middleware ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์†์‰ฝ๊ฒŒ ํ”„๋ก์‹œ ์„ค์ •์„ ํ•  ์ˆ˜ ์žˆ์œผ๋‹ˆ ๊ฑฑ์ •ํ•˜์ง€๋ง์ž. (webpack-dev-server๋„ ๋‚ด๋ถ€์ ์œผ๋กœ๋Š” ์–ด์ฐจํ”ผ http-proxy-middleware๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค)

    ๋‹ค๋งŒ ์ด ๋ฐฉ๋ฒ•์€ ์‹ค์ œ ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ๋„ ํด๋ผ์ด์–ธํŠธ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์†Œ์Šค๋ฅผ ์„œ๋น™ํ•˜๋Š” ์ถœ์ฒ˜์™€ API ์„œ๋ฒ„์˜ ์ถœ์ฒ˜๊ฐ€ ๊ฐ™์€ ๊ฒฝ์šฐ์— ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์ข‹๋‹ค. ๋ฌผ๋ก  ๋กœ์ปฌ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ์•ผ ์›นํŒฉ์ด ์š”์ฒญ์„ ํ”„๋ก์‹ฑํ•ด์ฃผ๋‹ˆ ์•„๋ฌด ์ด์ƒ์ด ์—†๊ฒ ์ง€๋งŒ, ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ๋นŒ๋“œํ•˜๊ณ  ์„œ๋ฒ„์— ์˜ฌ๋ฆฌ๊ณ  ๋‚˜๋ฉด ๋” ์ด์ƒ webpack-dev-server๊ฐ€ ๊ตฌ๋™ํ•˜๋Š” ํ™˜๊ฒฝ์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ํ”„๋ก์‹ฑ์ด๊ณ  ๋‚˜๋ฐœ์ด๊ณ  ์ด์ƒํ•œ ๊ณณ์œผ๋กœ API ์š”์ฒญ์„ ๋ณด๋‚ด๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

    ์˜ˆ๋ฅผ ๋“ค์–ด API ์„œ๋ฒ„์˜ ์ถœ์ฒ˜๋Š” https://api.evan.com์ด๊ณ  ํด๋ผ์ด์–ธํŠธ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์„œ๋น™ํ•˜๋Š” ์„œ๋ฒ„์˜ ์ถœ์ฒ˜๋Š” https://www.evan.com์ด๋ผ๋ฉด, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒํ™ฉ์ด ๋ฐœ์ƒํ•œ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

    fetch('/api/me');
    ๋กœ์ปฌํ™˜๊ฒฝ์—์„œ๋Š”...
    GET https://api.evan.com/me 200 OK
    
    ์‹ค์ œ ์„œ๋ฒ„์—๋Š” ํ”„๋ก์‹ฑ ๋กœ์ง์ด ์—†์Œ...
    GET https://www.evan.com/api/me 404 Not Found

    ๋ฌผ๋ก  ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง ๋‚ด์—์„œ process.env.NODE_ENV์™€ ๊ฐ™์€ ๋นŒ๋“œ ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ถ„๊ธฐ ๋กœ์ง์„ ์ž‘์„ฑํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ์ง€๋งŒ, ๊ฐœ์ธ์ ์œผ๋กœ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์— ์ด๋Ÿฐ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ ์ „์šฉ ์†Œ์Šค๊ฐ€ ํฌํ•จ๋˜๋Š” ๊ฒƒ์€ ๋ณ„๋กœ ์ข‹์ง€ ์•Š๋‹ค๊ณ  ์ƒ๊ฐํ•ด์„œ ํ”ผํ•˜๋Š” ํŽธ์ด๋‹ค.

    ์š”์ฒญ์„ img ํƒœ๊ทธ์— ๋„ฃ์œผ๋ฉด ์–ด๋–จ๊นŒ?

    ํ•„์ž๋Š” ์•ž์„œ SOP(Same-Origin Policy) ์ •์ฑ…์—๋Š” ๋‹ค๋ฅธ ์ถœ์ฒ˜์˜ ๋ฆฌ์†Œ์Šค์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๋ช‡ ๊ฐ€์ง€ ์˜ˆ์™ธ์กฐํ•ญ์ด ์กด์žฌํ•˜๊ณ , ๊ทธ ์ค‘ ํ•˜๋‚˜๊ฐ€ CORS ์ •์ฑ…์„ ์ง€ํ‚จ ์š”์ฒญ์ด๋ผ๊ณ  ์ด์•ผ๊ธฐํ–ˆ์—ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ  CORS ์ •์ฑ…์„ ์ง€ํ‚จ ์š”์ฒญ์„ ์ œ์™ธํ•œ SOP์˜ ์˜ˆ์™ธ ์กฐํ•ญ์€ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ์Šคํฌ๋ฆฝํŠธ, ๋ Œ๋”๋  ์ด๋ฏธ์ง€, ์Šคํƒ€์ผ ์‹œํŠธ ์ •๋„๊ฐ€ ์žˆ๋‹ค.

    ๊ทธ๋ ‡๋‹ค๋ฉด ๋‹ค๋ฅธ ์˜ˆ์™ธ ์กฐํ•ญ์ด ์ ์šฉ๋œ ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด CORS๋ฅผ ์šฐํšŒํ•  ์ˆ˜ ์žˆ์ง€ ์•Š์„๊นŒโ€ฆ? ์ด๋ ‡๊ฒŒ ๋ง์ด๋‹ค!

    <img src="https://evanmoon.tistory.com/rss">
    <script src="https://evanmoon.tistory.com/rss"></script>

    ๋ฌผ๋ก  ์ด๋Ÿฐ ์‹์œผ๋กœ ์ ‘๊ทผํ•˜๋ฉด CORS๋ฅผ ์œ„๋ฐ˜ํ•˜์ง€ ์•Š๊ณ  ์š”์ฒญ ์ž์ฒด๋Š” ์„ฑ๊ณตํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  ๋ธŒ๋ผ์šฐ์ €์˜ ๊ฐœ๋ฐœ์ž ๋„๊ตฌ์˜ ๋„คํŠธ์›Œํฌ ํƒญ์—์„œ ์ด ์š”์ฒญ๋“ค์˜ ํ—ค๋”๋ฅผ ์ž์„ธํžˆ ์‚ดํŽด๋ณด๋ฉด Sec-Fetch-Mode: no-cors๋ผ๋Š” ๊ฐ’์ด ํฌํ•จ๋˜์–ด ์žˆ๋Š” ๊ฒƒ์„ ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

    Sec-Fetch-Mode ํ—ค๋”๋Š” ์š”์ฒญ ๋ชจ๋“œ๋ฅผ ์„ค์ •ํ•˜๋Š” ํ•„๋“œ์ธ๋ฐ, ๋ธŒ๋ผ์šฐ์ €๋Š” ์ด ํ•„๋“œ์˜ ๊ฐ’์ด no-cors์ธ ๊ฒฝ์šฐ์—๋Š” ๋‹ค๋ฅธ ์ถœ์ฒ˜๋ผ๊ณ  ํ•ด๋„ CORS ์ •์ฑ… ์œ„๋ฐ˜ ์—ฌ๋ถ€๋ฅผ ๊ฒ€์‚ฌํ•˜์ง€ ์•Š๋Š”๋‹ค. ํ•˜์ง€๋งŒ ํ•œ ๊ฐ€์ง€ ์Šฌํ”ˆ ์ ์€ ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ์ด ํ—ค๋”์— ๊ฐ’์ด ํฌํ•จ๋œ ์š”์ฒญ์˜ ์‘๋‹ต์„ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ์—๊ฒŒ ์•Œ๋ ค์ฃผ์ง€ ์•Š๋Š”๋‹ค๋Š” ๊ฒƒ์ด๋‹ค. ์ฆ‰, ์šฐ๋ฆฌ๋Š” ์ฝ”๋“œ ๋ ˆ๋ฒจ์—์„œ ์ ˆ๋Œ€ ์ด ์‘๋‹ต์— ๋‹ด๊ธด ๋‚ด์šฉ์— ์ ‘๊ทผํ•  ์ˆ˜๊ฐ€ ์—†๋‹ค.

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

    ๋งˆ์น˜๋ฉฐ

    ์•„๋ฌด๋ž˜๋„ CORS ์ •์ฑ… ์œ„๋ฐ˜์œผ๋กœ ์ธํ•ด ์ƒ๊ธฐ๋Š” ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ๋•Œ ๊ฐ€์žฅ ๋ฒˆ๊ฑฐ๋กœ์šด ์ ์€ ๋ฌธ์ œ๋ฅผ ๊ฒช๋Š” ์‚ฌ๋žŒ๊ณผ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•ด์•ผํ•˜๋Š” ์‚ฌ๋žŒ์ด ๋‹ค๋ฅด๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

    ์•ž์„œ ์ด์•ผ๊ธฐํ–ˆ๋“ฏ CORS ์ •์ฑ…์€ ๋ธŒ๋ผ์šฐ์ €์˜ ๊ตฌํ˜„ ์ŠคํŽ™์ด๊ธฐ ๋•Œ๋ฌธ์— ์ •์ฑ… ์œ„๋ฐ˜์œผ๋กœ ์ธํ•ด ๋ฌธ์ œ๋ฅผ ๊ฒช๋Š” ์‚ฌ๋žŒ์€ ๋Œ€๋ถ€๋ถ„ ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž์ด์ง€๋งŒ, ์ •์ž‘ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž๊ฐ€ ์„œ๋ฒ„ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ์‘๋‹ต ํ—ค๋”์— ์˜ฌ๋ฐ”๋ฅธ Acccess-Control-Allow-Origin์ด ๋‚ด๋ ค์˜ฌ ์ˆ˜ ์žˆ๋„๋ก ์„ธํŒ…ํ•ด์ค˜์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

    ๋ฌผ๋ก  ํ•„์ž๊ฐ€ ์ด์•ผ๊ธฐํ–ˆ๋˜ webpack-dev-server์˜ ํ”„๋ก์‹ฑ ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜์—ฌ ์ž์ฒด์ ์œผ๋กœ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ์ง€๋งŒ, ์ด ๋ฐฉ๋ฒ•์€ ๋กœ์ปฌ ๊ฐœ๋ฐœ ํ™˜๊ฒฝ์—์„œ๋งŒ ํ†ตํ•˜๋Š” ๋ฐฉ๋ฒ•์ธ๋ฐ๋‹ค๊ฐ€, ๊ทผ๋ณธ์ ์ธ ๋ฌธ์ œ ํ•ด๊ฒฐ ๋ฐฉ๋ฒ•์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฒฐ๊ตญ ์šด์˜ ํ™˜๊ฒฝ์—์„œ CORS ์ •์ฑ… ์œ„๋ฐ˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž์˜ ๋„์›€์ด ํ•„์š”ํ•  ์ˆ˜ ๋ฐ–์— ์—†๋‹ค.

    ์‚ฌ์‹ค CORS ์ •์ฑ… ์œ„๋ฐ˜์„ ํ•ด๊ฒฐํ•˜๋Š” ๋ฐฉ๋ฒ• ์ž์ฒด๊ฐ€ ๊ทธ๋ ‡๊ฒŒ ์–ด๋ ต๊ณ  ๋ณต์žกํ•œ ํŽธ์€ ์•„๋‹ˆ๋ผ์„œ ํ”„๋ก ํŠธ์—”๋“œ ๊ฐœ๋ฐœ์ž๋‚˜ ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž ์ค‘ ํ•œ ๋ช…์ด๋ผ๋„ ์ด๋Ÿฌํ•œ ์ •์ฑ…์— ๋Œ€ํ•ด์„œ ์ž˜ ์•Œ๊ณ  ์žˆ๋Š” ๊ฒฝ์šฐ๋ผ๋ฉด ์ƒ๊ฐ๋ณด๋‹ค ๋น ๋ฅด๊ณ  ์ˆ˜์›”ํ•˜๊ฒŒ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค.

    ๊ทธ๋Ÿฌ๋‚˜ ํ•„์ž๊ฐ€ ๋Œ€ํ•™์ƒ ๋•Œ ์ฒ˜์Œ CORS ์ •์ฑ… ์œ„๋ฐ˜์„ ๊ฒฝํ—˜ํ–ˆ๋˜ ๊ฒƒ์ฒ˜๋Ÿผ ํ”„๋ก ํŠธ์—”๋“œ์™€ ๋ฐฑ์—”๋“œ ๋‘˜ ๋‹ค ์ด๋Ÿฐ ๋ฌธ์ œ์— ๋Œ€ํ•œ ๊ฒฝํ—˜์ด ์—†๋Š” ๊ฒฝ์šฐ์—๋Š” ์ข€์ฒ˜๋Ÿผ ๊ฐ์„ ์žก๊ธฐ๊ฐ€ ํž˜๋“ , ์ฐธ ๋ฌ˜ํ•œ ๋ฌธ์ œ์ธ ๊ฒƒ ๊ฐ™๋‹ค.

    ์ด์ƒ์œผ๋กœ CORS๋Š” ์™œ ์ด๋ ‡๊ฒŒ ์šฐ๋ฆฌ๋ฅผ ํž˜๋“ค๊ฒŒ ํ•˜๋Š”๊ฑธ๊นŒ? ํฌ์ŠคํŒ…์„ ๋งˆ์นœ๋‹ค.

    Evan Moon

    ๐Ÿข ๊ฑฐ๋ถ์ด์ฒ˜๋Ÿผ ์‚ด์ž

    ๊ฐœ๋ฐœ์„ ์ž˜ํ•˜๊ธฐ ์œ„ํ•ด์„œ๊ฐ€ ์•„๋‹Œ ๊ฐœ๋ฐœ์„ ์ฆ๊ธฐ๊ธฐ ์œ„ํ•ด ๋…ธ๋ ฅํ•˜๋Š” ๊ฐœ๋ฐœ์ž์ž…๋‹ˆ๋‹ค. ์‚ฌ์†Œํ•œ ์ƒ๊ฐ ์ •๋ฆฌ๋ถ€ํ„ฐ ํŠœํ† ๋ฆฌ์–ผ, ์‚ฝ์งˆ๊ธฐ ์ •๋„๋ฅผ ์ฃผ๋กœ ๋„์ ์ด๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.