๐Ÿค” ์ฟ ํ‚ค ์„ธ์…˜ ๊ณผ์ œ & CORS Credentials error

lim1313ยท2021๋…„ 10์›” 20์ผ
1

TILPLUS

๋ชฉ๋ก ๋ณด๊ธฐ
37/40


์„ธ์…˜ ์„ธํŒ…

npm i express-session

app.use(
  session({
    secret: '@codecode',
    resave: false,
    saveUninitialized: true,
    cookie: {
      domain: 'localhost',
      path: '/',
      maxAge: 24 * 6 * 60 * 10000,
      sameSite: 'none',
      httpOnly: true,
      secure: true,
    },
  })
);

โšก express-session options

  • secret
    : ํ•„์ˆ˜ํ•ญ๋ชฉ์œผ๋กœ cookie-parser์˜ ๋น„๋ฐ€ ํ‚ค์™€ ๊ฐ™์€ ์—ญํ• 
  • resave (fault)
    : ๋ชจ๋“  request๋งˆ๋‹ค ๊ธฐ์กด์— ์žˆ๋˜ session์— ์•„๋ฌด๋Ÿฐ ๋ณ€๊ฒฝ์‚ฌํ•ญ์ด ์—†์„ ์‹œ์—๋„ session์„ ๋‹ค์‹œ ์ €์žฅํ•˜๋Š” ์˜ต์…˜
  • saveunintialized (true)
    : ์„ธ์…˜์ด store์— ์ €์žฅ๋˜๊ธฐ ์ „์— uninitialized ์ƒํƒœ๋ฅผ session์„ ์ €์žฅํ•œ๋‹ค.
    : ๋ณดํ†ต ๋ฐฉ๋ฌธ์ž๋ฅผ ์ถ”์ ํ•  ๋•Œ ์‚ฌ์šฉ
  • store (default : MemoryStore)
    : default๊ฐ’์€ memorystore๋กœ ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅ๋œ๋‹ค.
    : ์ฆ‰, ๋ฉ”๋ชจ๋ฆฌ๋Š” ์„œ๋ฒ„๊ฐ€ ๊บผ์ง€๋ฉด ํœ˜๋ฐœ๋˜๊ธฐ ๋•Œ๋ฌธ์—, ๋ฆฌ๋กœ๋“œํ•˜๋ฉด ์ดˆ๊ธฐํ™”๋œ๋‹ค.

โšก CORS ์„ค์ •

https://localhost:3000 cross-origin ํ—ˆ์šฉ
๋ฉ”์„œ๋“œ๋Š” GET, POST, OPTIONS๋ฅผ ํ—ˆ์šฉ

app.use(
  cors({
    origin: 'https://localhost:3000',
    methods: ['GET', 'POST', 'OPTIONS'],
  })
);

withCredientals / credentials

๐Ÿค” ๋ฌธ์ œ์ƒํ™ฉ

cross-origin์—์„œ response๋ฅผ ํ•˜์˜€์ง€๋งŒ, ์•„๋ž˜์™€ ๊ฐ™์€ ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒ

๋ฌธ์ œ ํŒŒ์•…

์—๋Ÿฌ ๋ฉ”์‹œ์ง€์— ๋”ฐ๋ฅด๋ฉด Access-Control-Allow-Credentials์— true๊ฐ’์„ ์ฃผ์–ด์•ผ ํ•œ๋‹ค๊ณ  ๋˜์–ด ์žˆ๋‹ค.

์ž๊ฒฉ ์ฆ๋ช…

MDN withCredentials

์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ํฌ๋กœ์Šค ์˜ค๋ฆฌ์ง„ ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ๊ฒฝ์šฐ, ๊ธฐ๋ณธ์ ์œผ๋กœ ์ฟ ํ‚ค๋‚˜ HTTP ์ธ์ฆ ๊ฐ™์€ ์ž๊ฒฉ ์ฆ๋ช…(credential / ์ฟ ํ‚ค, ์ธ๊ฐ€ ํ—ค๋”, TLS ์ธ์ฆ์„œ)์ด ํ•จ๊ป˜ ์ „์†ก๋˜์ง€ ์•Š๋Š”๋‹ค.
HTTP ์š”์ฒญ์˜ ๊ฒฝ์šฐ ๋Œ€๊ฐœ ์ฟ ํ‚ค๊ฐ€ ํ•จ๊ป˜ ์ „์†ก๋˜๋Š”๋ฐ, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฌ์šฉํ•ด ๋งŒ๋“  ํฌ๋กœ์Šค ์˜ค๋ฆฌ์ง„ ์š”์ฒญ์€ ์˜ˆ์™ธ๋‹ค.
๋”ฐ๋ผ์„œ fetch๋ฅผ ์‚ฌ์šฉํ•ด ์š”์ฒญ์„ ๋ณด๋‚ด๋„ another.com ๊ด€๋ จ ์ฟ ํ‚ค๊ฐ€ ํ•จ๊ป˜ ์ „์†ก๋˜์ง€ ์•Š๋Š”๋‹ค.

์™œ ๊ทธ๋Ÿด๊นŒ?

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

๊ทธ๋Ÿผ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ  ์„œ๋ฒ„์—์„œ ์ด๋ฅผ ํ—ˆ์šฉํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, ์ž๊ฒฉ ์ฆ๋ช…์ด ๋‹ด๊ธด ํ—ค๋”๋ฅผ ๋ช…์‹œ์ ์œผ๋กœ ํ—ˆ์šฉํ•˜๊ฒ ๋‹ค๋Š” ์„ธํŒ…์„ ์„œ๋ฒ„์— ํ•ด์ค˜์•ผ ํ•œ๋‹ค.

์ฟ ํ‚ค๋ฅผ ์š”์ฒญ์— ํฌํ•จํ•˜๊ณ  ์‹ถ์œผ๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ์˜ ์‘๋‹ต๊ณผ ์š”์ฒญ์— ๊ฐ๊ฐ credentials: true, withCredentials: true์„ ๋„ฃ์–ด์ฃผ๋ฉด ๋œ๋‹ค.

๐Ÿ˜Ž ํ•ด๊ฒฐ ์ฝ”๋“œ

app.use(
  cors({
    origin: 'https://localhost:3000',
    methods: ['GET', 'POST', 'OPTIONS'],
    credentials: true,
  })
);
axios
      .post(
        'https://localhost:4000/users/login',
        {
          userId: this.state.username,
          password: this.state.password,
        },
        { 'Content-Type': 'application/json', withCredentials: true }
      )
      .then((res) => {
        if (res.status === 200) {
          this.props.loginHandler(true);
        }
      })

๐Ÿ˜Ž origin: * vs origin: true

์œ„์—์„œ ์ •๋ฆฌํ•œ ๊ฒƒ ์ฒ˜๋Ÿผ cross origin์ผ ๊ฒฝ์šฐ ์‘๋‹ต ํ—ค๋”๋กœ Access-Control-Allow-Credentials ์˜ต์…˜๋„ ์„ค์ •ํ•ด์ฃผ์…”์•ผ ์ฟ ํ‚ค๊ฐ€ ์ „์†ก๋œ๋‹ค. Access-Control-Allow-Credentials๋ฅผ true๋กœ ์„ค์ •ํ•˜๊ณ  Access-Control-Allow-Origin ์˜ต์…˜๋„ *๊ฐ€ ์•„๋‹Œ ์ •ํ™•ํ•œ ๋„๋ฉ”์ธ์„ ์ ์–ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.

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

๊ทธ๋ ‡๋‹ค๋ฉด ๋‹ค์Œ์€ ์–ด๋–จ๊นŒ?

const cors = require('cors');

app.use(cors({
  origin: true,
  credentials: true
}));

origin: true ์€ ์™€์ผ๋“œ์นด๋“œ *์™€ ๊ฐ™์€ ๊ฒƒ์ผ๊นŒ??
๋‹ต์€ => ์•„๋‹ˆ๋‹ค.

origin: true๋Š” ํ”„๋ก ํŠธ ๋„๋ฉ”์ธ ์ฃผ์†Œ๊ฐ€ ์ž๋™์œผ๋กœ Access-Control-Allow-Origin์— ๋“ค์–ด๊ฐ„๋‹ค. ์™€์ผ๋“œ์นด๋“œ์ธ *์™€๋Š” ๋‹ค๋ฅด๋‹ค.

์ฐธ๊ณ  ์ž๋ฃŒ

Access-Control-Allow-Origin:* ์™€ Access-Control-Allow-Credentials: true๋Š” ํ•จ๊ป˜ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๋‹ค.
CORS๋Š” ์‘๋‹ต์ด Access-Control-Allow-Credentials: true ์„ ๊ฐ€์งˆ ๊ฒฝ์šฐ, Access-Controll-Allow-Origin์˜ ๊ฐ’์œผ๋กœ *๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ•˜๊ฒŒ ๋ง‰๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

Access-Control-Allow-Credentials: true๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ๋Š” ์‚ฌ์šฉ์ž ์ธ์ฆ์ด ํ•„์š”ํ•œ ๋ฆฌ์†Œ์Šค ์ ‘๊ทผ์ด ํ•„์š”ํ•œ ๊ฒฝ์šฐ์ธ๋ฐ, ๋งŒ์•ฝ Access-Control-Allow-Origin: *๋ฅผ ํ—ˆ์šฉํ•œ๋‹ค๋ฉด, CSRF ๊ณต๊ฒฉ์— ๋งค์šฐ ์ทจ์•ฝํ•ด์ ธ ์•…์˜์ ์ธ ์‚ฌ์šฉ์ž๊ฐ€ ์ธ์ฆ์ด ํ•„์š”ํ•œ ๋ฆฌ์†Œ์Šค๋ฅผ ๋งˆ์Œ๋Œ€๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ ‡๊ธฐ ๋•Œ๋ฌธ์— CORS ์ •์ฑ…์—์„œ ์•„์˜ˆ ๋™์ž‘ํ•˜์ง€ ์•Š๋„๋ก ๋ง‰์•„๋ฒ„๋ฆฐ ๊ฒƒ์ž…๋‹ˆ๋‹ค.

Access-Contorl-Allow-Credentials: true์ธ ๊ฒฝ์šฐ์—๋Š” ๋ฐ˜๋“œ์‹œ Access-Control-Allow-Origin์˜ ๊ฐ’์ด ํ•˜๋‚˜์˜ origin ๊ฐ’์œผ๋กœ ๋ช…์‹œ๋˜์–ด ์žˆ์–ด์•ผ ์ •์ƒ์ ์œผ๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.


<์ฐธ๊ณ ์ž๋ฃŒ>
๋‹ค๋ฅธ ๋„๋ฉ”์ธ๊ฐ„ ์ฟ ํ‚ค ์ „์†ก
cors ์ •๋ฆฌ ๋ธ”๋กœ๊ทธ

profile
start coding

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