CORS ์—๋Ÿฌ & SOP

โ˜๏ธ yeyoยท2022๋…„ 3์›” 15์ผ
0
post-thumbnail

๐Ÿ˜ฑ ์™ธ๋ถ€ API ์‚ฌ์šฉํ•˜๋‹ค๋ณด๋ฉด ์ž์ฃผ ๋ณด๋Š” ์—๋Ÿฌ CORS!
์‚ฌ์‹ค CORS ๋ฌธ์ œ๊ฐ€ ์•„๋‹ˆ๋ผ SOP ๋ฌธ์ œ์ด๋ฉฐ SOP ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•œ ๋ฐฉ๋ฒ•์ด ๋ฐ”๋กœ CORS์ด๋‹ค!

๐Ÿ’ก SOP(Same-Origin Policy)

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


โ—๏ธ ์ถœ์ฒ˜๋Š” ํ”„๋กœํ† ์ฝœ, ํ˜ธ์ŠคํŠธ, ํฌํŠธ ์กฐํ•ฉ์œผ๋กœ ๋˜์–ด์žˆ์œผ๋ฉฐ ์ด ์ค‘ ํ•˜๋‚˜๋ผ๋„ ๋‹ค๋ฅผ ์‹œ ๋™์ผ ์ถœ์ฒ˜๋กœ ๋ณด์ง€ ์•Š๋Š”๋‹ค!

์˜ˆ๋ฅผ ๋“ค์–ด
1. ํ”„๋กœํ† ์ฝœ์ด ๋‹ค๋ฅธ๊ฒฝ์šฐ
https://www.example.com vs http://www.example.com
2. ํ˜ธ์ŠคํŠธ๊ฐ€ ๋‹ค๋ฅธ ๊ฒฝ์šฐ
https://www.example.com vs http://example.com
3. ํฌํŠธ๊ฐ€ ๋‹ค๋ฅธ ๊ฒฝ์šฐ
http://www.example.com vs http://www.example.com:82
http๋Š” ๊ธฐ๋ณธ ํฌํŠธ๊ฐ€ 80์ด๋ฉฐ 82์™€ ๊ฐ™์ง€ ์•Š๊ธฐ ๋•Œ๋ฌธ์— ๋™์ผ ์ถœ์ฒ˜๊ฐ€ ์•„๋‹˜.

์ด๋Ÿฌํ•œ SOP ์ •์ฑ…์œผ๋กœ ์ธํ•œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด์„œ๋Š” CORS ์„ค์ •์ด ํ•„์š”ํ•˜๋‹ค!

๐Ÿ’ก CORS(Cross-Origin Resource Sharing)

์ถ”๊ฐ€์ ์ธ HTTP ํ—ค๋”๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ, ๋‹ค๋ฅธ ์ถœ์ฒ˜์˜ ์ž์›์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๊ถŒํ•œ์„ ๋ถ€์—ฌํ•˜๋„๋ก ๋ธŒ๋ผ์šฐ์ €์— ์•Œ๋ ค์ฃผ๋Š” ์ฒด์ œ์ด๋‹ค.
์ฆ‰ SOP์— ์˜ํ•ด ๋ง‰ํ˜”๋˜ ๋‹ค๋ฅธ ์ถœ์ฒ˜์˜ ๋ฆฌ์†Œ์Šค๊ฐ€ CORS๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์ด๋‹ค!

์ž์ฃผ ๋งˆ์ฃผ์น˜๋Š” CORS ์—๋Ÿฌ๋„ ํ•ด์„ํ•ด๋ณด๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.
๋‹ค๋ฅธ ์ถœ์ฒ˜์˜ ๋ฆฌ์†Œ์Šค๋ฅผ ๊ฐ€์ ธ์˜ค๋ ค๊ณ  ํ–ˆ์ง€๋งŒ SOP ๋–„๋ฌธ์— ์ ‘๊ทผ์ด ๋ถˆ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค. CORS ์„ค์ •์„ ํ†ตํ•ด ์„œ๋ฒ„์˜ ์‘๋‹ต ํ—ค๋”์— 'Access-Control-Allow-Origin'์„ ์ž‘์„ฑํ•˜๋ฉด ์ ‘๊ทผ ๊ถŒํ•œ์„ ์–ป์„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

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

CORS๊ฐ€ ๋‹ค๋ฅธ ์ถœ์ฒ˜์˜ ๋ฆฌ์†Œ์Šค๋ฅผ ํ—ˆ์šฉํ•˜๋„๋ก ์„ค์ •ํ•˜๋Š” ๊ฒƒ์€ ์ดํ•ดํ–ˆ์ง€๋งŒ ๋‚ด๋ถ€์ ์œผ๋กœ ์–ด๋–ป๊ฒŒ ๋™์ž‘ํ•˜๋Š” ๊ฒƒ์ผ๊นŒ?
CORS๋Š” ํฌ๊ฒŒ 3๊ฐ€์ง€์˜ ๋™์ž‘ ๋ฐฉ์‹์ด ์กด์žฌํ•œ๋‹ค.

  1. ํ”„๋ฆฌํ”Œ๋ผ์ดํŠธ ์š”์ฒญ(Preflight Request)
  2. ๋‹จ์ˆœ ์š”์ฒญ(Simple Request)
  3. ์ธ์ฆ ์ •๋ณด๋ฅผ ํฌํ•จํ•œ ์š”์ฒญ(Credentialed Request)

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

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

๐Ÿ’ก Preflight ์š”์ฒญ์ด ํ•„์š”ํ•œ ์ด์œ 

  • ์‹ค์ œ ์š”์ฒญ์„ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋ณด๋‚ด๋Š” ๊ฒƒ๋ณด๋‹ค ๋ฆฌ์†Œ์Šค ์ธก๋ฉด์—์„œ ํšจ์œจ์ 
  • CORS ๋Œ€๋น„๊ฐ€ ๋˜์–ด์žˆ์ง€ ์•Š์€ ์„œ๋ฒ„๋ฅผ ๋ณดํ˜ธ ๊ฐ€๋Šฅ.
    (CORS๊ฐ€ ์ƒ๊ฒจ๋‚˜๊ธฐ ์ด์ „์— ๋งŒ๋“ค์–ด์ง„ ์„œ๋ฒ„๋“ค์€ SOP ์š”์ฒญ๋งŒ ๋“ค์–ด์˜ค๋Š” ์ƒํ™ฉ์„ ๊ณ ๋ คํ•˜๊ณ  ๋งŒ๋“ค์–ด์ ธ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ถŒํ•œ์ด ์—†์Œ์—๋„ ์šฐ์„  ์š”์ฒญ์ด ์ฒ˜๋ฆฌ๋  ์ˆ˜ ์žˆ์Œ)
    => ์ด๋Ÿฌํ•œ ์ด์œ ๋กœ Preflight ์š”์ฒญ์€ CORS์˜ ๊ธฐ๋ณธ ์‚ฌ์–‘์œผ๋กœ ๋“ค์–ด๊ฐ€๊ฒŒ ๋˜์—ˆ์Œ.

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

ํŠน์ • ์กฐ๊ฑด์ด ๋งŒ์กฑ๋˜๋ฉด Preflight ์š”์ฒญ์„ ์ƒ๋žตํ•˜๊ณ  ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ๊ฒƒ์„ ๋งํ•œ๋‹ค.
์กฐ๊ฑด

  • 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 ์„ค์ • ๋ฐฉ๋ฒ•

ํ”„๋ก ํŠธ

1) ํ”„๋ก์‹œ ์„œ๋ฒ„ ์‚ฌ์šฉํ•˜๊ธฐ

ํ”„๋ก์‹œ ์„œ๋ฒ„๋ฅผ ํ†ตํ•ด ์šฐํšŒํ•˜์—ฌ ์™ธ๋ถ€๋กœ ์š”์ฒญ์„ ๋ณด๋ƒ„์œผ๋กœ์จ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ฐ„๋‹จํ•˜๊ฒŒ๋Š” ํƒ€๊ฒŸ ์ถœ์ฒ˜ ์•ž์— ํ”„๋ก์‹œ ์„œ๋ฒ„ URL์„ ์ถ”๊ฐ€ํ•˜์—ฌ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค.
https://cors-anywhere.herokuapp.com ์„œ๋น„์Šค๋ฅผ ๊ฐ€์žฅ ๊ฐ„๋‹จํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์—ˆ์œผ๋‚˜ 2021.02๋ถ€ํ„ฐ๋Š” ํ•œ ๋ฒˆ ๋“ค์–ด๊ฐ€์„œ ํ—ˆ์šฉ ๋ฒ„ํŠผ์„ ๋ˆŒ๋Ÿฌ์•ผ ๊ฐ€๋Šฅํ•˜๋‹ค๊ณ  ํ•˜๋ฉฐ, cors-anywhere ํ”„๋กœ์ ํŠธ๋ฅผ forkํ•˜์—ฌ heroku์—์„œ ํ”„๋ก์‹œ์„œ๋ฒ„๋ฅผ ๋งŒ๋“ค ์ˆ˜๋„ ์žˆ๋‹ค. ํ—ค๋กœ์ฟ (heroku)์— github ์—ฐ๋™ํ•ด์„œ cors ํ”„๋ก์‹œ ์„œ๋ฒ„ ๋งŒ๋“ค๊ธฐ(with cors-anywhere)

์ด ์™ธ์—๋„ ๋‹ค์–‘ํ•œ ๋ฌด๋ฃŒ ํ”„๋ก์‹œ ์„œ๋ฒ„๊ฐ€ ์กด์žฌํ•œ๋‹ค.

2) http-proxy-middleware

http-proxy-middleware ๋ชจ๋“ˆ์„ ์‚ฌ์šฉํ•ด ํ”„๋ก์‹œ ์„œ๋ฒ„๋ฅผ ์ ์šฉํ•  ์ˆ˜๋„ ์žˆ๋‹ค.
[React.js] Cross Domain ์ด์Šˆ ํ•ด๊ฒฐํ•˜๊ธฐ

์„œ๋ฒ„

ํƒ€๊ฒŸ ์„œ๋ฒ„์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋Š” ๊ฒฝ์šฐ๋ผ๋ฉด ์„œ๋ฒ„์—์„œ ์‘๋‹ต ํ—ค๋”๋ฅผ ์„ค์ •ํ•œ๋‹ค.

1. Node.js

app.use((req, res, next) => {
// ๋ชจ๋“  ๋„๋ฉ”์ธ
  res.header("Access-Control-Allow-Origin", "*"); 

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

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

2. Express ์„œ๋ฒ„

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" });
});

์ฐธ๊ณ  ์ž๋ฃŒ

  • ์ฝ”๋“œ์Šคํ…Œ์ด์ธ  UR Class ์ž๋ฃŒ
profile
๐Ÿ‹ https://ye-yo.github.io/ ๋กœ ๋ธ”๋กœ๊ทธ ์ด์ „ํ–ˆ์Šต๋‹ˆ๋‹ค

0๊ฐœ์˜ ๋Œ“๊ธ€