Front End/Web

[Web Server] CORS

๐ŸŒ

SOP

SOP๋Š” Same-Origin Policy์˜ ์ค„์ž„๋ง๋กœ, ๋™์ผ ์ถœ์ฒ˜ ์ •์ฑ…์„ ๋œปํ•œ๋‹ค. ํ•œ ๋งˆ๋””๋กœ โ€˜๊ฐ™์€ ์ถœ์ฒ˜์˜ ๋ฆฌ์†Œ์Šค๋งŒ ๊ณต์œ ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹คโ€™๋Š” ์ •์ฑ…์œผ๋กœ ์—ฌ๊ธฐ์„œ ์ถœ์ฒ˜๋Š” ํ”„๋กœํ† ์ฝœ, ํ˜ธ์ŠคํŠธ, ํฌํŠธ์˜ ์กฐํ•ฉ์œผ๋กœ ๋˜์–ด ์žˆ๋‹ค. ์ด ์ค‘ ํ•˜๋‚˜๋ผ๋„ ๋‹ค๋ฅด๋‹ค๋ฉด ๋™์ผํ•œ ์ถœ์ฒ˜๋กœ ๋ณด์ง€ ์•Š๋Š”๋‹ค.

ex. https://ninefloor.com :e http://ninefloor.com โ†’ ํ”„๋กœํ† ์ฝœ์ด ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ๋™์ผ ์ถœ์ฒ˜๊ฐ€ ์•„๋‹˜ https://portfolio.ninefloor.com โ‰  https://ninefloor.com โ†’ ํ˜ธ์ŠคํŠธ๊ฐ€ ๋‹ค๋ฅด๊ธฐ ๋•Œ๋ฌธ์— ๋™์ผ ์ถœ์ฒ˜๊ฐ€ ์•„๋‹˜ http://ninefloor.com:81 โ‰  http://ninefloor.com โ†’ http์˜ ๊ธฐ๋ณธ ํฌํŠธ๋Š” 80์ด๊ธฐ ๋•Œ๋ฌธ์— ํฌํŠธ๊ฐ€ ๋‹ฌ๋ผ์„œ ๋™์ผ ์ถœ์ฒ˜๊ฐ€ ์•„๋‹˜ https://ninefloor.com = https://ninefloor.com:443 โ†’ https์˜ ๊ธฐ๋ณธ ํฌํŠธ๋Š” 443์ด๊ธฐ ๋•Œ๋ฌธ์— ๋ชจ๋‘ ๋‹ค ๊ฐ™์€ ๋™์ผ ์ถœ์ฒ˜์ž„

SOP๊ฐ€ ์ƒ๊ธด ์ด์œ 

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

ํ•˜์ง€๋งŒ SOP๋Š” ์• ์ดˆ์— ๋™์ผ ์ถœ์ฒ˜๊ฐ€ ์•„๋‹Œ ๋‹ค๋ฅธ ์‚ฌ์ดํŠธ์™€์˜ ๋ฆฌ์†Œ์Šค ๊ณต์œ ๋ฅผ ์ œํ•œํ•˜๊ธฐ ๋•Œ๋ฌธ์— ํƒ€ ์‚ฌ์ดํŠธ์— ์ •๋ณด๊ฐ€ ์ƒˆ์–ด๋‚˜๊ฐ€๋Š” ๊ฒƒ์„ ๋ฏธ์—ฐ์— ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด๋‹ค.

SOP๋Š” ๋ณด์•ˆ์„ ์œ„ํ•œ ์ •์ฑ…. ํ•˜์ง€๋งŒโ€ฆ

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

CORS

CORS๋Š” Cross-Origin Resource Sharing์˜ ์ค„์ž„๋ง๋กœ ๊ต์ฐจ ์ถœ์ฒ˜ ๋ฆฌ์†Œ์Šค ๊ณต์œ ๋ฅผ ๋œปํ•œ๋‹ค. MDN์—์„œ๋Š” โ€œ์ถ”๊ฐ€ย HTTPย ํ—ค๋”๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ, ํ•œย ์ถœ์ฒ˜์—์„œ ์‹คํ–‰ ์ค‘์ธ ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ๋‹ค๋ฅธ ์ถœ์ฒ˜์˜ ์„ ํƒํ•œ ์ž์›์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๊ถŒํ•œ์„ ๋ถ€์—ฌํ•˜๋„๋ก ๋ธŒ๋ผ์šฐ์ €์— ์•Œ๋ ค์ฃผ๋Š” ์ฒด์ œโ€๋กœ ์„ค๋ช…ํ•˜๊ณ  ์žˆ๋‹ค. ์ฆ‰, ๋ธŒ๋ผ์šฐ์ €๋Š” SOP์— ์˜ํ•ด ๊ธฐ๋ณธ์ ์œผ๋กœ ๋‹ค๋ฅธ ์ถœ์ฒ˜์˜ ๋ฆฌ์†Œ์Šค ๊ณต์œ ๋ฅผ ๋ง‰์ง€๋งŒ CORS๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ ‘๊ทผ ๊ถŒํ•œ์„ ์–ป์„ ์ˆ˜ ์žˆ๊ฒŒ ๋˜๋Š” ๊ฒƒ์ด๋‹ค.

CORS์˜ ๋™์ž‘ ๋ฐฉ์‹

1. ํ”„๋ฆฌํ”Œ๋ผ์ดํŠธ ์š”์ฒญ (Preflight Request)

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

๋งŒ์•ฝ ์š”์ฒญ์„ ๋ณด๋‚ธ ์ถœ์ฒ˜๊ฐ€ ์ ‘๊ทผ ๊ถŒํ•œ์ด ์—†๋‹ค๋ฉด ๋ธŒ๋ผ์šฐ์ €์—์„œ CORS ์—๋Ÿฌ๋ฅผ ๋„์šฐ๊ณ  ์‹ค์ œ ์š”์ฒญ์„ ์ „๋‹ฌํ•˜์ง€ ์•Š๋Š”๋‹ค.

๐Ÿค”
ํ”„๋ฆฌํ”Œ๋ผ์ดํŠธ ์š”์ฒญ์ด ํ•„์š”ํ•œ ์ด์œ  1. ์‹ค์ œ ์š”์ฒญ์„ ๋ณด๋‚ด๊ธฐ ์ „์— ๋ฏธ๋ฆฌ ๊ถŒํ•œ ํ™•์ธ์ด ๊ฐ€๋Šฅํ•ด ๋ฆฌ์†Œ์Šค ์ธก๋ฉด์—์„œ ํšจ์œจ์ ์ด๋‹ค. 2. CORS์— ๋Œ€๋น„๊ฐ€ ๋˜์ง€ ์•Š์€ ์„œ๋ฒ„๋ฅผ ๋ณดํ˜ธํ•  ์ˆ˜ ์žˆ๋‹ค. โ†’ ์ด๋Ÿฐ ์„œ๋ฒ„๋Š” SOP ์š”์ฒญ๋งŒ ๋“ค์–ด์˜ค๋Š” ์ƒํ™ฉ์„ ๊ณ ๋ คํ•˜์—ฌ ๋งŒ๋“ค์–ด์กŒ๊ธฐ ๋•Œ๋ฌธ์—, ๋‹ค๋ฅธ ์ถœ์ฒ˜์—์„œ ๋“ค์–ด์˜ค๋Š” ์š”์ฒญ์— ๋Œ€ํ•œ ๋Œ€๋น„๊ฐ€ ๋˜์–ด ์žˆ์ง€ ์•Š์•„ ์‘๋‹ต์„ ๋ณด๋‚ด๊ธฐ ์ „ ๋“ค์–ด์˜จ ์š”์ฒญ์„ ์šฐ์„  ์ฒ˜๋ฆฌํ•˜๊ฒŒ ๋œ๋‹ค. ๋งŒ์•ฝ ์ด๋Ÿฐ ์š”์ฒญ์ด DELETE๋‚˜ PUT์ฒ˜๋Ÿผ ์„œ๋ฒ„์˜ ์ •๋ณด๋ฅผ ์‚ญ์ œํ•˜๊ฑฐ๋‚˜ ์ˆ˜์ •ํ•˜๋Š” ์š”์ฒญ์ด๋ฉด ๋Œ€์ฐธ์‚ฌ๊ฐ€ ๋ฒŒ์–ด์งˆํ…๋ฐ, ํ”„๋ฆฌํ”Œ๋ผ์ดํŠธ๋กœ ๋จผ์ € ์š”์ฒญ์„ ๋ณด๋‚ด๋ฉด ์ด๋Ÿฌํ•œ ์ƒํ™ฉ์„ ๋ฏธ์—ฐ์— ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค.

2. ๋‹จ์ˆœ ์š”์ฒญ (Simple Request)

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

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

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

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

  • ํ”„๋ก ํŠธ : ์š”์ฒญ ํ—ค๋”์— withCredentials : true๋ฅผ ๋„ฃ์–ด์•ผ ํ•œ๋‹ค.
  • ์„œ๋ฒ„ : ์‘๋‹ต ํ—ค๋”์— Access-Control-Allow-Credentials : true๋ฅผ ๋„ฃ์–ด์ค˜์•ผ ํ•œ๋‹ค. โ†’ ์ด ๋•Œ, ์„œ๋ฒ„์ธก์—์„œ Access-Control-Allow-Origin๋ฅผ ์„ค์ •ํ•  ๋•Œ ๋ชจ๋“  ์ถœ์ฒ˜๋ฅผ ํ—ˆ์šฉํ•œ๋‹ค๋Š” ์™€์ผ๋“œ์นด๋“œ(*)๋กœ ์„ค์ •ํ•˜๋ฉด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค.

CORS ์„ค์ • ๋ฐฉ๋ฒ•

Node.js ์„œ๋ฒ„

const http = require('http');

const server = http.createServer((request, response) => {
// ๋ชจ๋“  ๋„๋ฉ”์ธ
  response.setHeader("Access-Control-Allow-Origin", "*");

// ํŠน์ • ๋„๋ฉ”์ธ
  response.setHeader("Access-Control-Allow-Origin", "https://codestates.com");

// ์ธ์ฆ ์ •๋ณด๋ฅผ ํฌํ•จํ•œ ์š”์ฒญ์„ ๋ฐ›์„ ๊ฒฝ์šฐ
  response.setHeader("Access-Control-Allow-Credentials", "true");
})

Express ์„œ๋ฒ„

Express ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•ด ์„œ๋ฒ„๋ฅผ ๋งŒ๋“œ๋Š” ๊ฒฝ์šฐ, cors ๋ฏธ๋“ค์›จ์–ด๋ฅผ ์‚ฌ์šฉํ•ด ๋ณด๋‹ค ๋” ๊ฐ„๋‹จํ•˜๊ฒŒ CORS๋ฅผ ์„ค์ • ํ•  ์ˆ˜ ์žˆ๋‹ค.

const cors = require("cors");
const app = express();

//๋ชจ๋“  ๋„๋ฉ”์ธ
app.use(cors());

//ํŠน์ • ๋„๋ฉ”์ธ
const options = {
  origin: "https://codestates.com", // ์ ‘๊ทผ ๊ถŒํ•œ์„ ๋ถ€์—ฌํ•˜๋Š” ๋„๋ฉ”์ธ
  credentials: true, // ์‘๋‹ต ํ—ค๋”์— Access-Control-Allow-Credentials ์ถ”๊ฐ€
  optionsSuccessStatus: 200, // ์‘๋‹ต ์ƒํƒœ 200์œผ๋กœ ์„ค์ •
};

app.use(cors(options));

//ํŠน์ • ์š”์ฒญ
app.get("/example/:id", cors(), function (req, res, next) {
  res.json({ msg: "example" });
});
๐Ÿค”
๋ฏธ๋“ค์›จ์–ด(Middleware)? ์„œ๋กœ ๋‹ค๋ฅธ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์„œ๋กœ ํ†ต์‹ ํ•˜๋Š” ๋ฐ ์‚ฌ์šฉ๋˜๋Š” ์†Œํ”„ํŠธ์›จ์–ด์ด๋‹ค. ์š”์ฒญ-์‘๋‹ต ์ฃผ๊ธฐ ์ค‘ request, response ๊ฐ์ฒด์— ๋Œ€ํ•œ ์ ‘๊ทผ ๊ถŒํ•œ์„ ๊ฐ€์ง€๊ณ  ๋ณ€ํ˜•์‹œํ‚ฌ ์ˆ˜ ์žˆ๋‹ค.


Uploaded by N2T