๐Ÿช ํ”„๋ก ํŠธ์—์„œ ์•ˆ์ „ํ•˜๊ฒŒ ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌํ•˜๊ธฐ (ft. React)

yaytomatoยท2020๋…„ 7์›” 5์ผ
823

React

๋ชฉ๋ก ๋ณด๊ธฐ
1/4
post-thumbnail

๐Ÿงžโ€โ™‚๏ธTL;DR

  • JWT๋ฅผ ์“ด๋‹ค.
  • refreshToken์€ secure httpOnly ์ฟ ํ‚ค๋กœ, accessToken์€ JSON payload๋กœ ์ „๋‹ฌ๋ฐ›๋Š”๋‹ค.
  • ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด mount ๋  ๋•Œ ๋งˆ๋‹ค refreshToken์„ ์ด์šฉํ•ด ์ƒˆ๋กœ์šด accessToken์„ ๋ฐ›์•„์™€ ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‚ด ์ง€์—ญ ๋ณ€์ˆ˜์— ์ €์žฅํ•˜๊ณ  ์‚ฌ์šฉํ•œ๋‹ค.
  • ์ด ๋ฐฉ์‹์œผ๋กœ CSRF ์ทจ์•ฝ์  ๊ณต๊ฒฉ๊ณผ (๋‹ค๋ฅธ ์„ ํƒ์ง€๋ณด๋‹ค) XSS ๊ณต๊ฒฉ์—์„œ ์•ˆ์ „ํ•  ์ˆ˜ ์žˆ๋‹ค. ํ•˜์ง€๋งŒ ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด XSS ๊ณต๊ฒฉ์— ์ทจ์•ฝํ•˜๋‹ค๋ฉด ์–ด๋–ค ๋ฐฉ์‹์„ ์„ ํƒํ•˜๋˜ ๋ณด์•ˆ์ด ์œ„ํ—˜ํ•˜๊ธฐ์— ๊ผญ XSS ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์•ผ ํ•œ๋‹ค.

ํด๋ผ์ด์–ธํŠธ์—์„œ ์•ˆ์ „ํ•œ ๋กœ๊ทธ์ธ / ์œ ์ € ์ธ์ฆ (Authentication) ๋ฐฉ์‹์— ๋Œ€ํ•ด ์–˜๊ธฐํ•˜๋ ค๋ฉด ๋‹ค์Œ ์„ธ ๊ฐ€์ง€๋ฅผ ๋จผ์ € ์ดํ•ดํ•ด์•ผ ํ•œ๋‹ค.

  1. ๋กœ๊ทธ์ธ์€ ์–ด๋–ป๊ฒŒ ์ด๋ฃจ์–ด์ง€๋‚˜
  2. ๋ณด์•ˆ์€ ์–ด๋–ป๊ฒŒ ๋šซ๋ฆฌ๋‚˜
  3. ๋ธŒ๋ผ์šฐ์ € ์ €์žฅ์†Œ ์ข…๋ฅ˜์™€ ๋ณด์•ˆ ์ด์Šˆ (localStorage, ์ฟ ํ‚ค, httpOnly ์ฟ ํ‚ค)

๋จผ์ € ์œ ์ € ์ธ์ฆ ์ฒ˜๋ฆฌ ํ”„๋กœ์„ธ์Šค๋ถ€ํ„ฐ ์ด์•ผ๊ธฐํ•ด๋ณด์ž. ๋‘ ๊ฐ€์ง€ ๋ฐฉ์‹์ด ์žˆ๋‹ค.

๐Ÿ”‘ ๋กœ๊ทธ์ธ์€ ์–ด๋–ป๊ฒŒ ์ด๋ฃจ์–ด์ง€๋‚˜

  1. ์„ธ์…˜ id๋ฅผ ์ด์šฉํ•˜๋Š” ๋ฐฉ์‹

    ์ด ๋ฐฉ์‹์—์„œ ์„œ๋ฒ„๋Š” ํŠน์ • ์œ ์ €์˜ ์ •๋ณด๋ฅผ ๋‹ด์€ ์„ธ์…˜์„ ์ƒ์„ฑํ•œ๋‹ค. (1) ์œ ์ €๊ฐ€ ๋กœ๊ทธ์ธํ•  ๋•Œ (2) ์„œ๋ฒ„๋Š” ์„ธ์…˜์„ ์ƒ์„ฑํ•œ ํ›„ (3) ๊ทธ ์„ธ์…˜์˜ id๋ฅผ ํด๋ผ์ด์–ธํŠธ์— ๋ณด๋‚ด์ฃผ๊ณ  (4) ํด๋ผ์ด์–ธํŠธ๋Š” ์ด id๋ฅผ ํด๋ผ์ด์–ธํŠธ์— ์ €์žฅํ•ด๋‘์—ˆ๋‹ค๊ฐ€ (5) ์ธ์ฆ์ด ํ•„์š”ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ๋•Œ ์„œ๋ฒ„์— id ๊ฐ’์„ ๋ณด๋‚ด๋ฉด (6) ์„œ๋ฒ„๋Š” ๊ทธ id๋ฅผ ํ†ตํ•ด ์„ธ์…˜์„ ๋ถˆ๋Ÿฌ์™€ ์œ ํšจํ•œ์ง€ ํ™•์ธํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ธ์ฆํ•œ๋‹ค.

  2. JWT๋ฅผ ์ด์šฉํ•˜๋Š” ๋ฐฉ์‹ (ft. refreshToken, accessToken)

    ๋น„์Šทํ•œ ๋ฐฉ์‹์œผ๋กœ (1) ์œ ์ €๊ฐ€ ๋กœ๊ทธ์ธํ•  ๋•Œ (2) ์„œ๋ฒ„๊ฐ€ ์ธ์ฆ ์ •๋ณด๋ฅผ ๋ณด๋‚ด์ฃผ๋Š”๋ฐ, ์•”ํ˜ธํ™”๋‚˜ ์‹œ๊ทธ๋‹ˆ์ฒ˜ ์ถ”๊ฐ€๊ฐ€ ๊ฐ€๋Šฅํ•œ ๋ฐ์ดํ„ฐ ํŒจํ‚ค์ง€์•ˆ์— ์ธ์ฆ ์ •๋ณด๋ฅผ ๋‹ด์•„ ๋ณด๋‚ด์ค€๋‹ค. (์ด ํŒจํ‚ค์ง€๊ฐ€ JSON Web Token ์ฆ‰ JWT๋‹ค.) (3) ๋‹ด๊ธฐ๋Š” ์ •๋ณด ์ค‘ accessToken๊ณผ refreshToken์ด ์ดํ›„ ์œ ์ € ์ธ์ฆ์— ์‚ฌ์šฉ๋˜๋Š”๋ฐ (4) ์ด ์ •๋ณด๋ฅผ ํด๋ผ์ด์–ธํŠธ์— ์ €์žฅํ•ด๋‘”๋‹ค.

    ์ข€ ๋” ์ž์„ธํžˆ ์„ค๋ช…ํ•˜๋ฉด ์‹ค์งˆ์ ์ธ ์ธ์ฆ ์ •๋ณด๋Š” accessToken์ธ๋ฐ ์ผ์ • ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด ๋งŒ๋ฃŒํ•˜๋Š” ๊ตฌ์กฐ๋ฅผ ๊ฐ€์ง€๊ณ ์žˆ๋‹ค. (๋กœ๊ทธ์ธ ํ›„ ๋ฉฐ์น  ๋’ค ๋กœ๊ทธ์ธ์ด ๋งŒ๋ฃŒ๋ผ์„œ ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•ด์•ผ ํ–ˆ๋˜ ๊ฒฝํ—˜์ด ์žˆ๋Š”๊ฐ€?) refreshToken์„ ์ด์šฉํ•ด ๋กœ๊ทธ์ธ์„ ์ง€์†์ ์œผ๋กœ ์œ ์ง€ํ•  ์ˆ˜๋„ ์žˆ๋‹ค. refreshToken์„ ์„œ๋ฒ„์— ๋ณด๋‚ด๋ฉด ๊ทธ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด accessToken์„ ๋ฐœ๊ธ‰ํ•ด ๋Œ๋ ค์ฃผ๋Š” ๊ฑฐ๋‹ค. refreshToken ์‚ฌ์šฉ์€ ์˜ต์…˜์ด๋‹ค.

    ๊ทธ๋Ÿผ ๋‹ค์‹œ ๋Œ์•„์™€ (5) ์ด accessToken์„ ์œ ์ €์—๊ฒŒ๋งŒ ๋ณด์—ฌ์ค„ ์ˆ˜ ์žˆ๋Š” ์ •๋ณด์— ์ ‘๊ทผํ•  ๋•Œ ์„œ๋ฒ„์— ๋ณด๋‚ด๋ฉด (6) ์„œ๋ฒ„๋Š” ๊ทธ ํ† ํฐ์ด ์œ ํšจํ•œ์ง€ ํ™•์ธํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ธ์ฆํ•œ๋‹ค.

๋‹ค์Œ์œผ๋กœ ๋ณด์•ˆ ๊ณต๊ฒฉ์˜ ์ข…๋ฅ˜์™€ ํŠน์ง•์— ๋Œ€ํ•ด ์‚ดํŽด๋ณด์ž. ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋ณด์•ˆ ์ทจ์•ฝ์  ์ค‘ ์œ ์ € ์ธ์ฆ์—์„œ ๋ณดํŽธ์ ์œผ๋กœ ์ด์šฉ๋˜๋Š” ์ทจ์•ฝ์ ์€ ๋‘ ๊ฐ€์ง€๋‹ค: XSS์™€ CSRF

๐Ÿ˜ˆ ๋ณด์•ˆ์€ ์–ด๋–ป๊ฒŒ ๋šซ๋ฆฌ๋‚˜

  1. XSS ๊ณต๊ฒฉ

    ๊ณต๊ฒฉ์ž(ํ•ด์ปค)๊ฐ€ ํด๋ผ์ด์–ธํŠธ ๋ธŒ๋ผ์šฐ์ €์— Javascript๋ฅผ ์‚ฝ์ž…ํ•ด ์‹คํ–‰ํ•˜๋Š” ๊ณต๊ฒฉ์ด๋‹ค. ๊ณต๊ฒฉ์ž๊ฐ€ <input>์„ ํ†ตํ•ด Javascript๋ฅผ ์„œ๋ฒ„๋กœ ์ „์†กํ•ด ์„œ๋ฒ„์—์„œ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•˜๊ฑฐ๋‚˜, url์— Javascript๋ฅผ ์ ์–ด ํด๋ผ์ด์–ธํŠธ์—์„œ ์Šคํฌ๋ฆฝํŠธ ์‹คํ–‰์ด ๊ฐ€๋Šฅํ•˜๋‹ค๋ฉด ๊ณต๊ฒฉ์ž๊ฐ€ ์‚ฌ์ดํŠธ์— ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฝ์ž…ํ•ด XSS ๊ณต๊ฒฉ์„ ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด๋•Œ ๊ณต๊ฒฉ์ž๋Š” Javascript๋ฅผ ํ†ตํ•ด ์‚ฌ์ดํŠธ์˜ ๊ธ€๋กœ๋ฒŒ ๋ณ€์ˆซ๊ฐ’์„ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ ๊ทธ ๊ฐ’์„ ์ด์šฉํ•ด ์‚ฌ์ดํŠธ์ธ ์ฒ™ API ์ฝœ์„ ์š”์ฒญํ•  ์ˆ˜๋„ ์žˆ๋‹ค. ๋‹ค์‹œ ๋งํ•˜๋ฉด ๊ณต๊ฒฉ์ž์˜ ์ฝ”๋“œ๊ฐ€ ๋‚ด ์‚ฌ์ดํŠธ์˜ ๋กœ์ง์ธ ์ฒ™ ํ–‰๋™ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฑฐ๋‹ค.

  2. CSRF ๊ณต๊ฒฉ

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

React์—์„œ(= ํด๋ผ์ด์–ธํŠธ) ์œ„ ํ”„๋กœ์„ธ์Šค๋“ค์„ ๋”ฐ๋ผ ์„ธ์…˜ id๋‚˜ accessToken ๊ฐ™์€ ์ธ์ฆ์ •๋ณด๋ฅผ ์ €์žฅํ•  ๋•Œ (์ธ์ฆ ๋ฐฉ์‹ 4๋ฒˆ ๋‹จ๊ณ„ ํ•ด๋‹น) ์ด์šฉํ•˜๋Š” ์ €์žฅ์†Œ๋Š” ๋ณดํ†ต localStorage๋‚˜ ์ฟ ํ‚ค๋‹ค. ํŽ˜์ด์ง€๋ฅผ ๋ฆฌํ”„๋ ˆ์‹œ ํ•˜๊ฑฐ๋‚˜ ์ฐฝ์„ ๋‹ซ๊ณ  ๋‹ค์‹œ ์ ‘์†ํ•  ๋•Œ๋„ ๋กœ๊ทธ์ธ ์ •๋ณด๊ฐ€ ์ด์–ด์ง€๋„๋ก ๋‘˜ ๋‹ค ๋ธŒ๋ผ์šฐ์ €์— ์ €์žฅํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค. ํ•˜์ง€๋งŒ ๋‘ ๋ฐฉ์‹์€ XSS์™€ CSRF ๊ณต๊ฒฉ์— ์ทจ์•ฝํ•  ์ˆ˜ ์žˆ๋‹ค.

๐Ÿ˜ฑ ๋ธŒ๋ผ์šฐ์ € ์ €์žฅ์†Œ ์ข…๋ฅ˜์™€ ๋ณด์•ˆ ์ด์Šˆ

  1. localStorage ์ €์žฅ ๋ฐฉ์‹

    ๋ธŒ๋ผ์šฐ์ € ์ €์žฅ์†Œ์— ์ €์žฅํ•˜๋Š” ๋ฐฉ์‹์ด๋‹ค. Javascript ๋‚ด ๊ธ€๋กœ๋ฒŒ ๋ณ€์ˆ˜๋กœ ์ฝ๊ธฐ / ์“ฐ๊ธฐ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

    ๐Ÿ˜ˆ : localStorage ์•ˆ์— ์„ธ์…˜ id, refreshToken ๋˜๋Š” accessToken์„ ์ €์žฅํ•ด๋‘๋ฉด XSS ์ทจ์•ฝ์ ์„ ํ†ตํ•ด ๊ทธ ์•ˆ์— ๋‹ด๊ธด ๊ฐ’์„ ๋ถˆ๋Ÿฌ์˜ค๊ฑฐ๋‚˜, ๋ถˆ๋Ÿฌ์˜จ ๊ฐ’์„ ์ด์šฉํ•ด API ์ฝœ์„ ์œ„์กฐํ•  ์ˆ˜ ์žˆ๋‹ค.

  2. ์ฟ ํ‚ค ์ €์žฅ ๋ฐฉ์‹

    ๋ธŒ๋ผ์šฐ์ €์— ์ฟ ํ‚ค๋กœ ์ €์žฅ๋˜๋Š”๋ฐ, ํด๋ผ์ด์–ธํŠธ๊ฐ€ HTTP ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ๋งˆ๋‹ค ์ž๋™์œผ๋กœ ์ฟ ํ‚ค๊ฐ€ ์„œ๋ฒ„์— ์ „์†ก๋œ๋‹ค. Javascript ๋‚ด ๊ธ€๋กœ๋ฒŒ ๋ณ€์ˆ˜๋กœ ์ฝ๊ธฐ / ์“ฐ๊ธฐ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜๋‹ค.

    ๐Ÿ˜ˆ : ์ฟ ํ‚ค ์ €์žฅ ๋ฐฉ์‹ ์—ญ์‹œ ์•ˆ์— ์„ธ์…˜ id, refreshToken, accessToken์„ ์ €์žฅํ•ด๋‘๋ฉด XSS ์ทจ์•ฝ์ ์ด ์žˆ์„ ๋•Œ ๋‹ด๊ธด ๊ฐ’๋“ค์„ ๋ถˆ๋Ÿฌ์˜ค๊ฑฐ๋‚˜, API ์ฝœ์„ ๋ณด๋‚ด๋ฉด ์ฟ ํ‚ค์— ๋‹ด๊ธด ๊ฐ’๋“ค์ด ํ•จ๊ป˜ ์ „์†ก๋˜์–ด ๋กœ๊ทธ์ธํ•œ ์ฒ™ ๊ณต๊ฒฉ์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

    ๐Ÿ˜ˆ : ์ฟ ํ‚ค์— ์„ธ์…˜ id๋‚˜ accessToken์„ ์ €์žฅํ•ด ์ธ์ฆ์— ์ด์šฉํ•˜๋Š” ๊ตฌ์กฐ์— CSRF ์ทจ์•ฝ์ ์ด ์žˆ๋‹ค๋ฉด ์ธ์ฆ ์ •๋ณด๊ฐ€ ์ฟ ํ‚ค์— ๋‹ด๊ฒจ ์„œ๋ฒ„๋กœ ๋ณด๋‚ด์ง„๋‹ค. ๊ณต๊ฒฉ์ž๋Š” ์œ ์ € ๊ถŒํ•œ์œผ๋กœ ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ค๊ฑฐ๋‚˜ ์•ก์…˜์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

    ๐Ÿ˜‡ : ์ฟ ํ‚ค์— refreshToken๋งŒ ์ €์žฅํ•˜๊ณ  ์ƒˆ๋กœ์šด accessToken์„ ๋ฐ›์•„์™€ ์ธ์ฆ์— ์ด์šฉํ•˜๋Š” ๊ตฌ์กฐ์—์„œ๋Š” CSRF ์ทจ์•ฝ์  ๊ณต๊ฒฉ์„ ๋ฐฉ์–ดํ•  ์ˆ˜ ์žˆ๋‹ค. refreshToken์œผ๋กœ accessToken์„ ๋ฐ›์•„๋„ accessToken์„ ์Šคํฌ๋ฆฝํŠธ์— ์‚ฝ์ž…ํ•  ์ˆ˜ ์—†๋‹ค๋ฉด accessToken์„ ์‚ฌ์šฉํ•ด ์œ ์ € ์ •๋ณด๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

  3. secure httpOnly ์ฟ ํ‚ค ์ €์žฅ ๋ฐฉ์‹

    ๋ธŒ๋ผ์šฐ์ €์— ์ฟ ํ‚ค๋กœ ์ €์žฅ๋˜๋Š” ๊ฑด ๊ฐ™์ง€๋งŒ, Javascript ๋‚ด์—์„œ ์ ‘๊ทผ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋‹ค. secure์„ ์ ์šฉํ•˜๋ฉด https ์ ‘์†์—์„œ๋งŒ ๋™์ž‘ํ•œ๋‹ค.

    ๐Ÿ˜‡ : httpOnly ์ฟ ํ‚ค ๋ฐฉ์‹์œผ๋กœ ์ €์žฅ๋œ ์ •๋ณด๋Š” XSS ์ทจ์•ฝ์  ๊ณต๊ฒฉ์œผ๋กœ ๋‹ด๊ธด ๊ฐ’์„ ๋ถˆ๋Ÿฌ์˜ฌ ์ˆ˜ ์—†๋‹ค.

    ๐Ÿ˜‡ : httpOnly ์ฟ ํ‚ค ์—ญ์‹œ refreshToken๋งŒ ์ €์žฅํ•˜๊ณ  accessToken์„ ๋ฐ›์•„์™€ ์ธ์ฆ์— ์ด์šฉํ•˜๋Š” ๊ตฌ์กฐ๋กœ CSRF ๊ณต๊ฒฉ ๋ฐฉ์–ด๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

    ๐Ÿ˜ˆ : ์ฟ ํ‚ค ์ €์žฅ ๋ฐฉ์‹๊ณผ ๊ฐ™์€ ์ด์œ ๋กœ ์„ธ์…˜ id, accessToken์€ ์ €์žฅํ•˜๋ฉด ์•ˆ ๋œ๋‹ค.

    ๐Ÿ˜ˆ : httpOnly ์ฟ ํ‚ค์— ๋‹ด๊ธด ๊ฐ’์— ์ ‘๊ทผํ•  ์ˆ˜๋Š” ์—†์ง€๋งŒ XSS ์ทจ์•ฝ์ ์„ ๋…ธ๋ ค API ์ฝœ์„ ์š”์ฒญํ•˜๋ฉด httpOnly ์ฟ ํ‚ค์— ๋‹ด๊ธด ๊ฐ’๋“ค๋„ ํ•จ๊ป˜ ๋ณด๋‚ด์ ธ ์œ ์ €์ธ ์ฒ™ ์ •๋ณด๋ฅผ ๋นผ์˜ค๊ฑฐ๋‚˜ ์•ก์…˜์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค.

์–ด๋–ค ์ €์žฅ ๋ฐฉ์‹์„ ํƒํ•ด๋„ XSS ์ทจ์•ฝ์ ์ด ์žˆ๋‹ค๋ฉด ๋ณด์•ˆ ์ด์Šˆ๊ฐ€ ์กด์žฌํ•œ๋‹ค (XSS๋กœ API ์ฝœ์„ ๋ณด๋‚ด๋Š” ๋ฐฉ์‹์œผ๋กœ ๋‹ค ๋šซ๋ฆฐ๋‹ค). ๊ทธ๋Ÿฌ๋ฏ€๋กœ ์œ ์ € ์ •๋ณด ์ €์žฅ ๋ฐฉ์‹์„ ๋ฐ”๊พธ๋Š” ๊ฒƒ๋งŒ์œผ๋กœ๋Š” ๋ฐฉ์–ดํ•  ์ˆ˜ ์—†๊ณ , ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„์—์„œ ์ถ”๊ฐ€์ ์œผ๋กœ XSS ๋ฐฉ์–ด ์ฒ˜๋ฆฌ๊ฐ€ ํ•„์ˆ˜๋‹ค.

์˜ˆ: <input>์—์„œ ์ž…๋ ฅ๋œ ๊ฐ’์ด html / Javascript๋กœ ์ธ์‹๋˜์ง€ ์•Š๋„๋ก ์„œ๋ฒ„์—์„œ escape ์ฒ˜๋ฆฌ๋ฅผ ํ•ด์ค€๋‹ค. ๋˜ url์„ ํ†ตํ•ด Javascript๋ฅผ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์—†๋„๋ก ๋ผ์šฐํŒ…์„ ๊ผผ๊ผผํ•˜๊ฒŒ ๊ด€๋ฆฌํ•œ๋‹ค. ๋‹คํ–‰์ธ ๊ฒƒ์€ React๋Š” ๊ณต๊ฒฉ์ž๊ฐ€ string์— html / Javascript๋ฅผ ๋‹ด์•„ JSX์— ์‚ฝ์ž…ํ•  ๊ฒฝ์šฐ ์ž๋™์œผ๋กœ escape ์ฒ˜๋ฆฌํ•œ๋‹ค. (XSS ๋ฐฉ์–ด ์ฒ˜๋ฆฌ๋Š” ๋˜ ๋‹ค๋ฅธ ์ฃผ์ œ๊ธฐ์— ์—ฌ๊ธฐ์„œ๋Š” ์ด ์ •๋„์—์„œ ๋งˆ๋ฌด๋ฆฌํ•œ๋‹ค.)

๐Ÿค” ๊ทธ๋ž˜์„œ ๋กœ๊ทธ์ธ์„ ์–ด๋–ป๊ฒŒ ํ•œ๋‹ค๋Š” ๊ฑฐ์•ผ?

๋ณธ๋ก ์— ๋“ค์–ด๊ฐ€๊ธฐ ์œ„ํ•œ ์ค€๋น„๋Š” ๋งˆ์ณค๋‹ค.

์ข…ํ•ฉํ•ด๋ณด๋ฉด ์„ธ์…˜ id๋ฅผ ๋ธŒ๋ผ์šฐ์ €์— ์ €์žฅํ•˜๋Š” ๋ฐฉ์‹์€ ์–ด๋–ค ๋ฐฉ์‹์ด๋˜์ง€ ๋ณด์•ˆ ์œ„ํ—˜์š”์†Œ๊ฐ€ ์žˆ์œผ๋ฏ€๋กœ JWT ์ด์šฉํ•œ ์ธ์ฆ ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•  ๊ฒƒ์ด๋‹ค. refreshToken๋งŒ์„ secure httpOnly ์ฟ ํ‚ค์— ์ €์žฅํ•ด CSRF ๊ณต๊ฒฉ์„ ๋ฐฉ์–ดํ•  ๊ฒƒ์ด๋‹ค. accessToken์€ ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‚ด ๋กœ์ปฌ ๋ณ€์ˆ˜์— ์ €์žฅํ•ด ์‚ฌ์šฉํ•˜๋ฉฐ, API๋ฅผ ์š”์ฒญํ•  ๋•Œ Authorization ํ—ค๋”์— ๋„ฃ์–ด ๋ณด๋‚ด์ค€๋‹ค. XSS ์ทจ์•ฝ์ ์„ ์ด์šฉํ•œ API ์š”์ฒญ ๊ณต๊ฒฉ์€ ํด๋ผ์ด์–ธํŠธ์™€ ์„œ๋ฒ„์—์„œ ์ถ”๊ฐ€์ ์œผ๋กœ ๋ฐฉ์–ด ํ•ด์•ผ ํ•œ๋‹ค.

์ •๋ฆฌ

  • JWT๋กœ ์œ ์ € ์ธ์ฆ
  • refreshToken์„ secure httpOnly ์ฟ ํ‚ค๋กœ, accessToken์€ JSON payload๋กœ ๋ฐ›์•„์™€์„œ ์›น ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‚ด ๋กœ์ปฌ ๋ณ€์ˆ˜๋กœ ์ด์šฉ
  • ์ด๋ฅผ ํ†ตํ•ด CSRF ์ทจ์•ฝ์  ๊ณต๊ฒฉ ๋ฐฉ์–ดํ•˜๊ณ , XSS ์ทจ์•ฝ์  ๊ณต๊ฒฉ์œผ๋กœ ์ €์žฅ๋œ ์œ ์ € ์ •๋ณด ์ฝ๊ธฐ๋Š” ๋ง‰์„ ์ˆ˜ ์žˆ์Œ
  • ํ•˜์ง€๋งŒ XSS ์ทจ์•ฝ์ ์„ ํ†ตํ•ด API ์ฝœ์„ ๋ณด๋‚ผ ๋•Œ๋Š” ๋ฌด๋ฐฉ๋น„ํ•˜๋‹ˆ XSS ์ž์ฒด๋ฅผ ๋ง‰๊ธฐ ์œ„ํ•ด ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ ๋ชจ๋‘ ๋…ธ๋ ฅํ•ด์•ผ ํ•จ

๐Ÿ‘ฉ๐Ÿปโ€๐Ÿ’ป React์— ์ ์šฉํ•˜๊ธฐ

์ค€๋น„๋ฌผ

secure ์ฟ ํ‚ค ์ „๋‹ฌ์„ ํ•˜๋ ค๋ฉด ํ”„๋ก ํŠธ(React)์™€ ๋กœ๊ทธ์ธ API๋ฅผ ์ œ๊ณตํ•  ๋ฐฑ์—”๋“œ(์„œ๋ฒ„ API)๋Š” ๊ฐ™์€ ๋„๋ฉ”์ธ์„ ๊ณต์œ ํ•ด์•ผํ•œ๋‹ค. (์˜ˆ: ํด๋ผ์ด์–ธํŠธ: https://shop.abc.com, ์„œ๋ฒ„ API: https://api.abc.com)
๋ฐฑ์—”๋“œ๋Š” HTTP ์‘๋‹ต Set-Cookie ํ—ค๋”์— refreshToken ๊ฐ’์„ ์„ค์ •ํ•˜๊ณ  accessToken ์„ JSON payload์— ๋‹ด์•„ ๋ณด๋‚ด์ค˜์•ผ ํ•œ๋‹ค.

ํด๋ผ์ด์–ธํŠธ์—์„œ ์ฒ˜๋ฆฌํ•˜๊ธฐ

๋จผ์ €, React ์ตœ์ƒ๋‹จ index.js์—์„œ axios์— withCredentials๋ฅผ true๋กœ ์„ค์ •ํ•ด์ค˜์•ผ refreshToken cookie๋ฅผ ์ฃผ๊ณ ๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค.

import React from "react";
import ReactDOM from "react-dom";
import axios from "axios";

import App from "./App";

axios.defaults.baseURL = "https://www.abc.com";
axios.defaults.withCredentials = true;

๋กœ๊ทธ์ธ ๋กœ์ง์€ ๊ฐ„๋‹จํ•˜๋‹ค.

onLogin = (email, password) => {
	const data = {
		email,
		password,
	};
	axios.post('/login', data).then(response => {
		const { accessToken } = response.data;

		// API ์š”์ฒญํ•˜๋Š” ์ฝœ๋งˆ๋‹ค ํ—ค๋”์— accessToken ๋‹ด์•„ ๋ณด๋‚ด๋„๋ก ์„ค์ •
		axios.defaults.headers.common['Authorization'] = `Bearer ${accessToken}`;

		// accessToken์„ localStorage, cookie ๋“ฑ์— ์ €์žฅํ•˜์ง€ ์•Š๋Š”๋‹ค!

	}).catch(error => {
		// ... ์—๋Ÿฌ ์ฒ˜๋ฆฌ
	});
}

๐ŸŽ ๋ณด๋„ˆ์Šค

๋กœ๊ทธ์ธ ๋งŒ๋ฃŒ, ๋กœ๊ทธ์ธ ์—ฐ์žฅ ์ฒ˜๋ฆฌํ•˜๊ธฐ

์ด ์„น์…˜์€ zeneo๋‹˜ ์งˆ๋ฌธ์„ ๋ฐ›๊ณ  ์ถ”๊ฐ€๋˜์—ˆ์Šต๋‹ˆ๋‹ค.

JWT ์ธ์ฆ ๋ฐฉ์‹์—์„œ ์‹ค์งˆ์ ์œผ๋กœ ์ธ์ฆ๋˜์—ˆ๋‚˜๋ฅผ ๊ฒฐ์ •ํ•˜๋Š” ๊ฒƒ์€ accessToken์ด๋‹ค. ํ•˜์ง€๋งŒ ์šฐ๋ฆฌ๊ฐ€ ํƒํ•œ ๊ตฌ์กฐ์—์„œ ๋ธŒ๋ผ์šฐ์ €์— ์ €์žฅ๋œ ๊ฐ’์€ ์ฟ ํ‚ค์— ์ €์žฅ๋œ refreshToken๋ฟ์ด๊ธฐ์— ๋กœ์ปฌ์— ์ €์žฅ๋œ accessToken์€ ๋ธŒ๋ผ์šฐ์ € ์ฐฝ์ด ๊บผ์ง€๊ฑฐ๋‚˜ ํŽ˜์ด์ง€๊ฐ€ ๋ฆฌํ”„๋ ˆ์‹œ ๋˜๋Š” ๋“ฑ ํŽ˜์ด์ง€๊ฐ€ ๋ฆฌ๋กœ๋“œ ๋˜๋ฉด ์‚ฌ๋ผ์ง„๋‹ค. ๋˜ํ•œ, accessToken์€ ์ผ์ • ์‹œ๊ฐ„์ด ์ง€๋‚˜๋ฉด ๋งŒ๋ฃŒ๋œ๋‹ค. ๊ทธ๋ž˜์„œ (1) ์ด๋ฉ”์ผ, ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ž…๋ ฅํ•ด์„œ accessToken์„ ๋ฐ›์•„์˜ค๋Š” ๋ณดํ†ต ๋กœ๊ทธ์ธ ์ฒ˜๋ฆฌ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๋ณด๋‹ค ์™„์„ฑ๋„ ์žˆ๋Š” ์‚ฌ์ดํŠธ๋ฅผ ๋งŒ๋“ค๊ธฐ ์œ„ํ•ด (2) accessToken์ด ๋งŒ๋ฃŒ๋์„ ๋•Œ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ• ์ง€ (์˜ˆ๋ฅผ ๋“ค์–ด ์€ํ–‰ ์‚ฌ์ดํŠธ๊ฐ™์ด ๋ณด์•ˆ์ด ์ค‘์š”ํ•œ ์„œ๋น„์Šค๋ผ๋ฉด ์•„์˜ˆ ๋‹ค์‹œ ๋กœ๊ทธ์ธํ•˜๋„๋ก ๋กœ๊ทธ์ธ ํŽ˜์ด์ง€๋กœ ์ด๋™์‹œํ‚ฌ ์ˆ˜๋„ ์žˆ๊ณ , ์•„๋‹ˆ๋ฉด ์œ ์ € ๋ชจ๋ฅด๊ฒŒ ์„œ๋ฒ„์—์„œ ์ƒˆ๋กœ์šด accessToken์„ ๋ฐ›์•„์™€์„œ ๋กœ๊ทธ์ธ์ด ์—ฐ์žฅ๋˜๋„๋ก ํ•  ์ˆ˜๋„ ์žˆ์Œ), (3) ํŽ˜์ด์ง€ ๋ฆฌ๋กœ๋“œ ๋  ๋•Œ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ• ์ง€ (2๋ฒˆ๊ณผ ๊ฐ™์ด ์—ฌ๋Ÿฌ ๊ฐ€์ง€ ์ฒ˜๋ฆฌ ๋ฐฉ์‹์ด ์žˆ์Œ)๋„ ๊ฒฐ์ •ํ•ด์•ผ ํ•œ๋‹ค.

์ด ์˜ˆ์ œ์—์„œ๋Š” ์œ ์ €๊ฐ€ ๋‹ค์‹œ ์ง์ ‘ ๋กœ๊ทธ์ธํ•˜๋„๋ก ์œ ๋„ํ•˜์ง€ ์•Š๊ณ  ์กฐ์šฉํžˆ ์ž๋™์œผ๋กœ ๋กœ๊ทธ์ธ ์—ฐ์žฅํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ด๋ณด๊ฒ ๋‹ค. (์˜์–ด๋กœ silent refresh๋ผ๊ณ  ๋ถ€๋ฅธ๋‹ค.)

์ฒ˜๋ฆฌํ•  "๋กœ๊ทธ์ธ" ์ผ€์ด์Šค๋“ค

  1. ์ด๋ฉ”์ผ, ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ์ฒดํฌํ•˜๋Š” ๋ณดํ†ต ๋กœ๊ทธ์ธ
  2. accessToken์ด ๋งŒ๋ฃŒ๋์„ ๋•Œ ๋กœ๊ทธ์ธ ์—ฐ์žฅ ์ฒ˜๋ฆฌ
  3. ํŽ˜์ด์ง€ ๋ฆฌ๋กœ๋“œ ๋  ๋•Œ ๋กœ๊ทธ์ธ ์—ฐ์žฅ ์ฒ˜๋ฆฌ

์ค€๋น„๋ฌผ

์œ„์—์„œ ์ด์•ผ๊ธฐํ•œ 3๊ฐ€์ง€ ์ผ€์ด์Šค์— ๋Œ€์‘ํ•˜๊ธฐ ์œ„ํ•ด API๊ฐ€ 2๊ฐœ ํ•„์š”ํ•˜๋‹ค.

  1. POST /login: ์ด๋ฉ”์ผ, ๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋ณด๋‚ด๋ฉด refreshToken๊ณผ accessToken์„ ๋ฆฌํ„ดํ•œ๋‹ค.
  2. POST /silent-refresh: ์ฟ ํ‚ค์— ๋‹ด๊ธด refreshToken์ด ์ž๋™์œผ๋กœ ๋ณด๋‚ด์ง€๋ฉด ์ƒˆ๋กœ์šด refreshToken๊ณผ accessToken์„ ๋ฆฌํ„ดํ•œ๋‹ค.

๋‘ API ๋ชจ๋‘ HTTP ์‘๋‹ต Set-Cookie ํ—ค๋”์— refreshToken ๊ฐ’์„ ์„ค์ •ํ•˜๊ณ  accessToken ์„ JSON payload์— ๋‹ด์•„ ๋ณด๋‚ด์ค˜์•ผ ํ•œ๋‹ค.

ํด๋ผ์ด์–ธํŠธ์—์„œ ์ฒ˜๋ฆฌํ•˜๊ธฐ

1. ๋กœ๊ทธ์ธ & 2. ๋กœ๊ทธ์ธ ๋งŒ๋ฃŒ๋˜๊ธฐ ์ „์— ์—ฐ์žฅ

const JWT_EXPIRY_TIME = 24 * 3600 * 1000; // ๋งŒ๋ฃŒ ์‹œ๊ฐ„ (24์‹œ๊ฐ„ ๋ฐ€๋ฆฌ ์ดˆ๋กœ ํ‘œํ˜„)

onLogin = (email, password) => {
    const data = {
        email,
        password,
    };
    axios.post('/login', data)
        .then(onLoginSuccess)
        .catch(error => {
            // ... ์—๋Ÿฌ ์ฒ˜๋ฆฌ
        });
}

onSilentRefresh = () => {
    axios.post('/silent-refresh', data)
        .then(onLoginSuccess)
        .catch(error => {
            // ... ๋กœ๊ทธ์ธ ์‹คํŒจ ์ฒ˜๋ฆฌ
        });
}

onLoginSuccess = response => {
    const { accessToken } = response.data;

    // accessToken ์„ค์ •
    axios.defaults.headers.common['Authorization'] = `Bearer ${accessToken}`;

    // accessToken ๋งŒ๋ฃŒํ•˜๊ธฐ 1๋ถ„ ์ „์— ๋กœ๊ทธ์ธ ์—ฐ์žฅ
    setTimeout(onSilentRefresh, JWT_EXPIRRY_TIME - 60000);
}

3. ํŽ˜์ด์ง€ ๋ฆฌ๋กœ๋“œ ๋  ๋•Œ ๋กœ๊ทธ์ธ ์—ฐ์žฅ

// ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์ด ์‹คํ–‰๋  ๋•Œ๋งˆ๋‹ค ๋‹ค์‹œ ๋กœ๊ทธ์ธ ์‹œ๋„
class App extends Componet {
    componentDidMount() {
        onSilentRefresh();
    }
    // ...
}

๐Ÿฅณ ๋งˆ์น˜๋ฉฐ

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

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

์ฐธ๊ณ  ์ž๋ฃŒ

๐ŸŽจ ๋กœ์ปฌ์—์„œ ํ…Œ์ŠคํŒ…ํ•˜๋ ค๋ฉด...

๋‹ค์Œ ๊ธ€: "https๋กœ React ๋กœ์ปฌ ํ…Œ์ŠคํŒ…ํ•˜๊ธฐ"

profile
2021 ๋ชฉํ‘œ: ๋ฏฟ์Œ๊ณผ ์ดํƒ€์‹ฌ์œผ๋กœ ๊ฝ‰์ฐฌ ํ•œ ํ•ด ๋˜๊ธฐ

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

comment-user-thumbnail
2020๋…„ 7์›” 5์ผ

์™€์šฐ ์ •๋ง ์ข‹์€ ๋‚ด์šฉ์ด๋„ค์š”!!

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2020๋…„ 7์›” 5์ผ

ํด๋ผ์ด์–ธํŠธ ๋ณด์•ˆ๐Ÿ”๋„ ์ •๋ง ์ค‘์š”ํ•œ๋ฐ... ์•„๋‚Œ์—†์ด ๊ณต์œ ํ•ด์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค ๐Ÿ™‡

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2020๋…„ 7์›” 6์ผ

์œ ์šฉํ•œ ์ •๋ณด ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค! ์ €๋„ ๊ฐœ๋ฐœํ•˜๋Š” ํ”„๋กœ์ ํŠธ์— ์ž˜ ์ฐธ๊ณ ํ•ด๋ณด๋ ค๊ณ  ํ•ด์š”!!

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2020๋…„ 7์›” 6์ผ

์˜ค์˜ค ๋ฉ‹์ ธ์š”

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2020๋…„ 7์›” 9์ผ

์ •๋ง ์ข‹์€ ๋‚ด์šฉ์ด๋„ค์š”!! ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2020๋…„ 7์›” 10์ผ

์•Œ๋ ค์ฃผ์‹  ๋ฐฉ๋ฒ•๋Œ€๋กœ ๊ตฌํ˜„ํ•ด ๋ณด๊ณ  ์žˆ๋Š” ์ดˆ๋ณด ๊ฐœ๋ฐœ์ž ์ž…๋‹ˆ๋‹ค.
๋ช‡๊ฐ€์ง€ ๊ถ๊ธˆํ•ด์„œ ์—ฌ์ญ™๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

  1. axios.defaults.headers.common['Authorization']์˜ ๊ฐ’์ด ์ƒˆ๋กœ๊ณ ์นจ์„ ํ•˜๊ฑฐ๋‚˜ ๋‹ค๋ฅธ ํŽ˜์ด์ง€๋กœ ์˜ฎ๊ฒจ๊ฐˆ๋•Œ ์œ ์ง€๊ฐ€ ์•ˆ๋˜๋Š”๋ฐ, ์–ด๋–ป๊ฒŒ ํ•ด๊ฒฐํ•˜์‹œ๋‚˜์š”? ์ž‘์„ฑํ•˜์‹  ํฌ์ŠคํŠธ์—์„œ๋Š” ๋ณด์•ˆ์ƒ ์ด์œ ๋กœ ๋ฆฌ๋•์Šค๋‚˜ ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€๋ฅผ ์•ˆ์จ์•ผํ•œ๋‹ค๊ณ  ํ•˜์‹œ๋Š” ๊ฒƒ์œผ๋กœ ์ดํ•ดํ–ˆ๋Š”๋ฐ์š”. (์ผ๋‹จ์€ ๋งค๋ฒˆ accessํ† ํฐ์„ ์ƒˆ๋กœ ๋ฐœ๊ธ‰ํ•ด์ค˜์•ผ ํ•œ๋‹ค๊ณ  ์ดํ•ด๋Š” ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒ ํ•˜๋ฉด csrf ํ† ํฐ์ฒ˜๋Ÿผ ์‚ฌ์šฉ๋˜๋‹ˆ๊นŒ csrf ํ† ํฐ์€ ๋”ฐ๋กœ ์•ˆํ•ด๋„ ๋ ๊นŒ์š”?)

  2. ๋ฐฑ์—”๋“œ๋Š” ์–ด๋–ค์ ˆ์ฐจ๋กœ ์ž‘๋™ํ•˜๋„๋ก ๊ตฌ์„ฑํ•ด์•ผ ํ• ๊นŒ์š”? ์ž‘์„ฑํ•˜์‹  ํฌ์ŠคํŠธ์—์„œ๋Š” json์œผ๋กœ access ํ† ํฐ์„ ๋ณด๋‚ด์ฃผ์–ด์•ผ ํ•œ๋‹ค๊ณ  ํ•˜์…จ์œผ๋‹ˆ ํŽ˜์ด์ง€๊ฐ€ ์ด๋™๋˜๊ฑฐ๋‚˜ ์ƒˆ๋กœ๊ณ ์นจ ๋  ๋•Œ๋งˆ๋‹ค ๋กœ๊ทธ์ธ ์—ฌ๋ถ€๋ฅผ ์ฒดํฌํ•˜๋Š” api๋ฅผ ๋งŒ๋“ค์–ด์„œ refresh ํ† ํฐ์„ ์ฟ ํ‚ค์—์„œ ์ฝ์–ด์™€์„œ ๊ทธ์—๋”ฐ๋ผ ๊ฐ’์„ access ํ† ํฐ์„ ์ƒˆ๋กœ ๋ฐœ๊ธ‰ํ•ด์ฃผ๋„๋ก ํ•ด์•ผ ํ• ๊นŒ์š”?

access ํ† ํฐ๊ณผ refresh ํ† ํฐ ์‚ฌ์šฉ์˜ˆ๊ฐ€ ๋งŽ์ด ์—†์–ด์„œ ํ˜ผ์ž ๋…ํ•™ํ•ด์„œ ๋งŒ๋“œ๋Š๋ผ ๋ถ€์กฑํ•œ ๋ถ€๋ถ„์ด ์žˆ์—ˆ๋Š”๋ฐ ์ข‹์€ ๋‚ด์šฉ ๊ณต์œ  ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

2๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2020๋…„ 7์›” 18์ผ

์˜ค ์ฝ๊ธฐ ์ข‹๊ฒŒ ์ •๋ฆฌํ•ด์ฃผ์…จ๋„ค์š” ใ…Žใ…Ž ์ข‹์€ ๊ธ€ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค~!

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2020๋…„ 7์›” 18์ผ

@yaytomato ๋‹˜ ์ถ”๊ฐ€์ ์ธ ์˜๊ฒฌ์„ ๋“œ๋ฆฌ๊ณ ์ž ๋Œ“๊ธ€๋‹ฌ์•„๋ด…๋‹ˆ๋‹ค! ์ด๊ธ€์„ ์ฝ๋Š” ๋‹ค๋ฅธ ๊ฐœ๋ฐœ์ž ๋ถ„๋“ค๋„ ํ•œ๋ฒˆ ๊ณ ๋ฏผํ•ด ๋ณด์‹œ๋ฉด ์ข‹์„๊ฑฐ ๊ฐ™์Šต๋‹ˆ๋‹ค ~ ๊ทธ๋ฆฌ๊ณ  ๋ฒจ๋กœ๊ทธ ํŠธ๋ Œ๋”ฉ์— ๋‚˜์˜ค์‹ ๊ฑฐ ์ถ•ํ•˜๋“œ๋ฆฝ๋‹ˆ๋‹ค !!

ํ† ํฐ ๋ฐฉ์‹์€ ์ •๋ง ์•ˆ์ „ํ•œ๊ฐ€? Refresh token ์ด ํƒˆ์ทจ๋ฅผ ๋‹นํ•˜๋ฉด ์–ด๋–ป๊ฒŒ๋˜์ง€ ?

๋ณธ๋ฌธ์˜ ๋‚ด์šฉ์„ ๋‹ค์‹œ ์š”์•ฝํ•˜๋ฉด
์ตœ์ดˆ ๋กœ๊ทธ์ธ์‹œ์— access token/ refresh token์„ ์ฃผ๊ณ  ํ‰์†Œ์—” access token ์œผ๋กœ API๋ฅผ ์ด์šฉํ•˜๋‹ค๊ฐ€ ๋งŒ๋ฃŒ๋˜๋ฉด refresh token ์œผ๋กœ ๋‹ค์‹œ access token์„ ๋ฐœ๊ธ‰ ๋ฐ›๋Š” ๊ตฌ์กฐ์ž…๋‹ˆ๋‹ค. ์ด๋•Œ refresh token ์€ ์ฟ ํ‚ค์— ์ €์žฅํ•œ๋‹ค๊ณ  ํ•˜์…จ์Šต๋‹ˆ๋‹ค.

์ด ์ƒํ™ฉ์—์„œ ์ „์ œ๋˜์–ด์•ผ ํ•˜๋Š” ๊ฒƒ์ด refresh๋ฅผ ์•ˆ์ „ํ•˜๊ฒŒ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๋ณด๊ด€ํ•˜๋Š” ๊ฒƒ์ธ๋ฐ ์›น๋ธŒ๋ผ์šฐ์ €์—์„œ๋Š” ์‚ฌ์‹ค์ƒ ์ด ํ† ํฐ์„ ์•ˆ์ „ํ•˜๊ฒŒ ๋ณด๊ด€ํ•  ๊ณณ์€ ์—†์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ ์ €๋Š” ์•„์ง ์›น์—์„œ๋Š” JWT๋ฅผ ์ ๊ทน์ ์œผ๋กœ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. <-- ์ œ ๊ฐœ์ธ์ ์ธ ์ƒ๊ฐ (Refresh token์„ ํด๋ผ์ด์–ธํŠธ์˜ ๋กœ์ปฌ์—์„œ ๊ฐ•๋ ฅํ•˜๊ฒŒ ์ง€ํ‚ค๋Š” ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค๋ฉด ์ถ”๊ฐ€์ ์œผ๋กœ ๋Œ“๊ธ€ ํ™˜์˜ํ•ฉ๋‹ˆ๋‹ค ~)

๊ทธ๋Ÿผ ๋ญ์•ผ... ํ† ํฐ์ธ์ฆ์€ ๊ฒฐ๊ตญ ๋ณด์•ˆ์ด ์•ˆ๋˜๋Š”๊ฑด๊ฐ€? https ๋กœ ํ•˜๋ฉด ๋‹ค ๋๋‚˜๋Š”๊ฑฐ ์•„๋‹Œ๊ฐ€? ์ด๋Ÿฐ ์ƒ๊ฐ์„ ํ•˜์‹ค ์ˆ˜ ์žˆ๋Š”๋ฐ
์•„๋‹™๋‹ˆ๋‹ค. ์ €๋„ ํ•œ์ฐธ ๋ถ€์กฑํ•˜์ง€๋งŒ ์ œ๊ฐ€ ์ƒ๊ฐํ•˜๋Š” ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ฑ™๊ฒจ์•ผํ•  ๋ณด์•ˆ์€ ์นจํ•ด ์‹œ๊ฐ„์„ ์งง๊ฒŒ ํ•˜๋Š”๊ฒŒ ํ•˜๋Š”๊ฒƒ ์ž…๋‹ˆ๋‹ค.
๊ทธ๋ž˜์„œ ํ”ผํ•ด๋ฅผ ์ค„์ด๋Š” ๊ฒƒ์ด์ง€์š”~

"๋ณด์•ˆ์— ์€์ด์•Œ์€ ์—†๋‹ค"

๋” ๋งŽ์€ ๊ฐœ๋ฐœ์ž๋“ค์ด ์‚ฌ์šฉ์ž์˜ ์ •๋ณด๋ฅผ ์ง€ํ‚ค๊ณ  ๋ณด์•ˆ์— ๊ด€์‹ฌ์„ ๊ฐ€์ง€๊ณ  ์•ˆ์ „์žฅ์น˜๋ฅผ ํ•˜๋Š” ๊ฒƒ์€ ์ •๋ง์ •๋ง ์ค‘์š”ํ•œ ๊ฒƒ์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

2๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2020๋…„ 7์›” 18์ผ

์ž˜ ์ •๋ฆฌ๋œ ๊ธ€์ด๋„ค์š”! ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค :)

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2020๋…„ 7์›” 29์ผ

์ข‹์€ ์ •๋ณด ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2020๋…„ 8์›” 6์ผ

๊ฐœ์ธ์ ์œผ๋กœ๋Š” xss์— ์ทจ์•ฝํ•œ๋ฐฉ์‹์€ ์ „๋ถ€ ์ œ๊ฑฐํ•˜๊ณ  cookie๋กœ ์ „๋ถ€ ์ €์žฅํ•œ๋‹ค์Œ
csrf token์„ jwtํ† ํฐ์— ํฌํ•จ์‹œํ‚ค๋Š”๊ฑธ ์„ ํ˜ธํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋ฆฌ๊ณ  ํ”„๋ก ํŠธ์—์„œ๋Š” jwtํ† ํฐ์— ํฌํ•จ๋œ csrf ํ† ํฐ์„ ํ—ค๋”์— ๋„ฃ์–ด์„œ ๋ณด๋‚ด๊ณ 
์„œ๋ฒ„์—์„œ๋Š” jwt ํ† ํฐ ๋‚ด csrf์™€ ํ—ค๋”๋กœ ๋“ค์–ด์˜จ csrf์˜ ๊ฐ’๋น„๊ต๋ฅผ ํ†ตํ•ด csrf๋ฐฉ์–ด๋ฅผ ํ•ฉ๋‹ˆ๋‹ค.
์ง€๊ธˆ ์•Œ๋ ค์ฃผ์‹œ๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ๋Š” ๊ฒฐ๊ตญ xss์˜ ์ทจ์•ฝ์ ์ด ๋‚จ์Šต๋‹ˆ๋‹ค.

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2020๋…„ 8์›” 11์ผ

์ €๋Š” ๋ฆฌํ”„๋ ˆ์‰ฌํ† ํฐ๊ณผ ์—‘์„ธ์Šค ํ† ํฐ์„ ๋ชจ๋‘ ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— ๋„ฃ๊ณ , ajax call์‹œ ์—‘์„ธ์Šคํ† ํฐ์„ ํ—ค๋”์— ์ „๋‹ฌํ•˜๋Š” ์‹์œผ๋กœ ํ•˜๊ณ  expired๋˜๋ฉด ์ž๋™์œผ๋กœ ์—ฐ์žฅํ•ด์ฃผ๋Š” ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”๋ฐ ์ด ๊ฒฝ์šฐ์—๋„ ๊ดœ์ฐฎ์ง€ ์•Š์„๊นŒ์š”?

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2020๋…„ 8์›” 16์ผ

์ •๋ง ์ €๊ฐ™์€ ๋‰ด๋น„ํ•œํ…Œ ๋„ˆ๋ฌด๋„ˆ๋ฌด ์ข‹์€ ์ •๋ณด๊ธ€์ด๋„ค์š”,.... ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค ๊ณต๋ถ€ํ•˜๊ณ ์‹ถ์–ด์ง€๋„ค์šฅ

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2020๋…„ 8์›” 19์ผ

์ข‹์€ ๋‚ด์šฉ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2020๋…„ 8์›” 23์ผ

ํ˜„์žฌ ํ”„๋กœ์ ํŠธ ์ง„ํ–‰ ์ค‘์— ๋กœ๊ทธ์ธ ๋ณด์•ˆ ๊ด€๋ จ ํ•ด๊ฒฐ๋ฒ•์„ ์ฐพ๊ณ  ์žˆ์—ˆ๋Š”๋ฐ ๋„ˆ๋ฌด๋‚˜ ์ข‹์€ ํฌ์ŠคํŠธ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค !!

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2020๋…„ 8์›” 24์ผ

๋กœ๊ทธ์ธ ๊ตฌํ˜„ํ•˜๋Š”๋ฐ ๊ฑฐ์ง 1์ฃผ์ผ์€ jwt, ์‹œํ์–ด ์ฝ”๋”ฉ, ๋ชจ์˜ํ•ดํ‚น ์ด๋Ÿฐ๊ฑฐ ์ฐพ๋‹ค ์ด ๊ธ€์„ ๋ฐœ๊ฒฌํ–ˆ๋„ค์š”. ์ฐพ๋‹ค๋ณด๋ฉด ํ•ญ์ƒ ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ์„ ํด๋ผ์ด์–ธํŠธ์— ์–ด๋–ป๊ฒŒ ๋ณด๊ด€ํ•ด์•ผํ•˜๋Š” ์ด์Šˆ์— ๋Œ€ํ•œ ๋‹ต์„ ๋ชป ์ฐพ์•„์„œ ์—ฌ๊ธฐ์ €๊ธฐ ๋‹ค๋…”์Šต๋‹ˆ๋‹ค. https only๋‚˜ secure๋‚˜ ๋„ฃ์„๊บผ๋ฉด ์—‘์„ธ์Šค ํ† ํฐ์„ ์ €๊ธฐ ๋‹ค ๋„ฃ์ง€.
๊ตณ์ด ๋ฆฌํ”„๋ ˆ์‹œ๋ฅผ ์จ์•ผํ•˜๋Š” ์˜๋ฌธ๋„ ์ƒ๊ธฐ๊ณ .(์ €๋ ‡๊ฒŒ ๊นŒ์ง€ ํ•ด๋„ ์ฟ ํ‚ค ํ„ธ ์ˆ˜ ์žˆ๋Š” ๋Šฅ๋ ฅ์ž๋ฉด ๋ฆฌํ”„๋ ˆ์‹œ๋Š” ๊ทธ๋ƒฅ ํ„ธ๋ฆฌ๋Š”๊ฑฐ๋‹ˆ๊นŒ์š”.)
์–ด์งœํ”ผ ํ„ธ๋ฆด ์ˆ˜ ์žˆ๋Š”๊ฑฐ ์„œ๋ฒ„์—์„œ๋Š” ์–ด๋–ป๊ฒŒ ํ•ด์ค˜์•ผ ํ•˜๋‚˜ ๊ณ ๋ฏผ๊ณ ๋ฏผ ํ–ˆ์—ˆ์Šต๋‹ˆ๋‹ค.
๋ณด์•ˆ๊ณผ ํŽธ์˜์„ฑ&์„ฑ๋Šฅ์€ ์–ธ์ œ๋‚˜ ๋ฐ˜๋น„๋ก€ํ•˜๋Š” ๊ฑฐ๋ผ ์ ์ ˆํ•œ ์„ ์—์„œ ํƒ€ํ˜‘์„ ๋ด์•ผ ํ•˜๋”๋ผ๊ตฌ์š”.
์ด ๊ธ€ ์ฝ๊ณ  ๋งŽ์ด ์ƒ๊ฐ์ด ์ •๋ฆฌ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ณ ๋ง™์Šต๋‹ˆ๋‹ค.

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2020๋…„ 8์›” 25์ผ

๊น”๋”ํ•œ ์ •๋ฆฌ์™€ ์ดํ•ดํ•˜๊ธฐ ์‰ฌ์šด ์„ค๋ช… ๋•๋ถ„์— ๋กœ๊ทธ์ธ ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•˜๋ฉฐ ๋งŽ์€ ์ฐธ๊ณ ๊ฐ€ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!!!

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2020๋…„ 9์›” 1์ผ

์ข‹์€ ๋‚ด์šฉ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2020๋…„ 9์›” 2์ผ

์ข‹์€ ๋‚ด์šฉ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2020๋…„ 9์›” 8์ผ

๐Ÿ‘ ์ข‹์€ ๊ธ€ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค :)

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2020๋…„ 9์›” 26์ผ

์™€๋“œ๋ฐ•๊ณ  ๊ฐ‘๋‹ˆ๋‹น

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2020๋…„ 10์›” 5์ผ

์นœ์ ˆํ•œ ํฌ์ŠคํŠธ ๋•๋ถ„์— ์ดํ•ด๊ฐ€ ์ž˜ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค ;ใ…; ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2020๋…„ 10์›” 7์ผ

์•ˆ๋…•ํ•˜์„ธ์š”, ์šฐ์„  ์ข‹์€ ํฌ์ŠคํŠธ ๊ฐ์‚ฌ๋“œ๋ฆฝ๋‹ˆ๋‹ค! ์งˆ๋ฌธ์ด ์žˆ๋Š”๋ฐ์š”, ์„ธ์…˜ ID๋ฅผ ๋ธŒ๋ผ์šฐ์ €์— ์ €์žฅํ•˜๋Š” ๊ฒƒ์ด ์œ„ํ—˜์š”์†Œ๊ฐ€ ์žˆ์–ด JWT๋ฅผ ์ด์šฉํ•œ๋‹ค๊ณ  ํ•˜์…จ๋Š”๋ฐ, ๊ทธ๋Ÿผ ์„ธ์…˜ ID๋ฅผ HTTPOnly๋กœ ์ €์žฅํ•˜๋ฉด ๋ฌธ์ œ๊ฐ€ ์—†๋Š” ๊ฑด๊ฐ€์š”?

2๊ฐœ์˜ ๋‹ต๊ธ€

ํ˜น์‹œ github์ฃผ์†Œ ์•Œ ์ˆ˜ ์žˆ์„๊นŒ์š”~~

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2020๋…„ 11์›” 10์ผ

์ตœ๊ณ ๋„ค์š” ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!!!

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2020๋…„ 12์›” 24์ผ

์•ˆ๋…•ํ•˜์„ธ์š” ๋ฌธ์˜๋‚ด์šฉ์ด ์žˆ์–ด์„œ ๊ธ€์„ ๋‚จ๊น๋‹ˆ๋‹ค..

๋กœ๊ทธ์ธ ์œ ์ง€์‹œ refresh ํ† ํฐ ์‚ฌ์šฉํ•ด์„œ ๊ฐฑ์‹ ์„ ํ•œ๋‹ค๊ณ  ํ•˜์…จ๋Š”๋ฐ
refresh ํ† ํฐ๋„ ์œ ํšจ๊ธฐ๊ฐ„์ด ์žˆ๋Š”๋ฐ ๊ทธ ๊ธฐ๊ฐ„์กฐ์ฐจ ๋งŒ๋ฃŒ๋˜๋ฉด ์–ด๋–ป๊ฒŒ ํ•ด์•ผํ•˜๋‚˜์š”?

์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์•„์›ƒ ์ด์ „๊นŒ์ง€ ๋กœ๊ทธ์ธ์œ ์ง€๋ฅผ ํ•ด์•ผํ•˜๋Š” ์ƒํ™ฉ์ž…๋‹ˆ๋‹ค.

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2021๋…„ 2์›” 9์ผ

์ •๋ฆฌ๋ฅผ ๋„ˆ๋ฌด ์ž˜ํ•ด์ฃผ์…จ์–ด์š” ๋ฆฌ์•กํŠธ ์˜ˆ์ œ๋„ ๋„ˆ๋ฌด ์ข‹์Šต๋‹ˆ๋‹ค ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2021๋…„ 2์›” 9์ผ

์ข‹์€ ๊ธ€ ์ž˜ ๋ดค์Šต๋‹ˆ๋‹ค!
๋‹ค๋งŒ ๊ถ๊ธˆํ•œ ์ ์ด ํ•˜๋‚˜ ์žˆ์–ด์š”. refresh token์€ httpOnly ์ฟ ํ‚ค์— ์ €์žฅํ•œ๋‹ค๊ณ  ํ•˜์…จ๋Š”๋ฐ access token์ด ๋งŒ๋ฃŒ๋˜์—ˆ์„ ๋•Œ refresh token์€ JS๋กœ ์–ด๋–ป๊ฒŒ ๊ฐ€์ ธ์™€์„œ refresh ์š”์ฒญ์„ ํ•ด์•ผ ํ• ๊นŒ์š”?

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2021๋…„ 2์›” 18์ผ

๊ธ€ ์ •๋ง ๋„ˆ๋ฌด ์ข‹์€ ๋‚ด์šฉ์ด์—์š” ์ด๋Ÿฐ ์œ ์šฉํ•œ ๊ธ€ ์˜ฌ๋ ค์ฃผ์…”์„œ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!!! ๋•๋ถ„์— ๊ณต๋ถ€๊ฐ€ ๋งŽ์ด ๋ฌ์–ด์š”!!

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2021๋…„ 3์›” 24์ผ

๊ตฟ^^
์ข‹์€๊ธ€ ๊ฐ์‚ฌํ•ด์š”๐ŸŒบ๐Ÿ€

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2021๋…„ 4์›” 19์ผ

JSON WEB TOKEN ๊ด€๋ จ ๊ธ€ ์ค‘์— ๊ฐ€์žฅ ์‰ฝ๊ณ  ํ™•์‹คํ•˜๊ฒŒ ์•Œ๋ ค์ฃผ๋Š” ๊ธ€์ด ์•„๋‹Œ๊ฐ€ ์‹ถ์Šต๋‹ˆ๋‹ค.
์ €๋Š” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ธ์ฆ๋ฐฉ๋ฒ•์œผ๋กœ JWT๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๋Š”๋ฐ ํ† ํฐ์ด ํƒˆ์ทจ๋‹นํ•˜๋ฉด
๋ณด์•ˆ์— ์ทจ์•ฝํ•˜๋‹ค๋Š”๊ฒƒ์„ ์ฒด๊ฐํ•˜๊ณ  ๊ฒ€์ƒ‰ํ•˜๋‹ค๊ฐ€ ์ด๊ณณ์œผ๋กœ ์˜ค๊ฒŒ ๋˜์—ˆ์–ด์š”.

์ œ๊ฐ€ ํ•˜๋ ค๊ณ  ํ•˜๋Š” ๋ฐฉ์‹์ด ๊ดœ์ฐฎ์„์ง€ ์กฐ์–ธ ์ข€ ๊ตฌํ•ด ๋ณด์•„์š”

  1. ๋กœ๊ทธ์ธ์‹œ Access Token ๊ณผ Refresh Token์„ ๋ฐœ๊ธ‰ํ•˜๊ณ  Refresh Token์„ ๋””๋ฐ”์ด์Šค์— ์ €์žฅ
  2. Access Token ๋งŒ๋ฃŒ ๊ธฐ๊ฐ„์ด ์ง€๋‚˜๋ฉด Refresh Token์œผ๋กœ Access Token์„ ์žฌ ๋ฐœํ–‰
  3. ํŠน์ • ํ–‰์œ„๋ฅผ ํ•  ๋•Œ(์ž์ฃผ ํ•˜์ง€ ์•Š์ง€๋งŒ ์•ฑ์„ ์ •์ƒ์ ์œผ๋กœ ์‚ฌ์šฉํ•œ๋‹ค๋ฉด ์ด์šฉํ•˜๊ฒŒ ๋  ๊ธฐ๋Šฅ)
    ๋งˆ๋‹ค Refresh Token๋„ ์—…๋ฐ์ดํŠธ๋ฅผ ์‹œ์ผœ์ฃผ๋Š” ๋กœ์ง์œผ๋กœ ๊ตฌ์„ฑ

๊ทธ๋ฆฌ๊ณ  Refresh Token์„ ๋กœ๊ทธ์•„์›ƒ ํ•˜์ง€ ์•Š์€์ฑ„๋กœ ์žฌ๋ฐœํ–‰ํ•˜๋ฉด ์ƒ๊ธฐ๋Š” ๋ฌธ์ œ๊ฐ€ ์žˆ์„๊นŒ์š”?

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2021๋…„ 4์›” 28์ผ

๊ธ€ ์ž˜์ฝ์—ˆ์Šต๋‹ˆ๋‹ค.
ํ•˜๋‚˜ ๊ณต์œ ๋“œ๋ฆฌ๊ณ  ์‹ถ์€๊ฒŒ
accessToken์„ ํƒˆ์ทจ๋‹นํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค๋ผ๊ณ  ์ƒ๊ฐํ•˜๊ณ  ๊ฐ€๋ฉด accessToken์ž์ฒด์˜ ๋งŒ๋ฃŒ์‹œ๊ฐ„์„ ๊ทน๋‹จ์ ์œผ๋กœ ์งง๊ฒŒ(1๋ถ„ ๋ฏธ๋งŒ) ์ฃผ์–ด์„œ ํƒˆ์ทจ๋ฅผ ๋‹นํ•ด๋„ ์‚ฌ์šฉํ•  ์ˆ˜ ์—†๊ฒŒ ํ•˜๋Š”๋ฐฉ๋ฒ•์€ ์–ด๋–จ์ง€ ์—ฌ์ญค๋ณด๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.
์ด๋ ‡๊ฒŒ ํ–ˆ์„ ๊ฒฝ์šฐ refreshToken์€ secure, httpOnly๋กœ ์ธํ•ด ๋น„๊ต์  ํƒˆ์ทจ ๊ฐ€๋Šฅ์„ฑ์ด ์ ๊ธฐ๋•Œ๋ฌธ์— refreshToken์„ ์ข€ ๋” ๋งŽ์ด ํ™œ์šฉํ•˜๋Š” ๋ฐฉ์•ˆ์œผ๋กœ ์ƒ๊ฐํ–ˆ์„ ๋•Œ accessToken์€ ๊ธฐ์กด ์ž‘์„ฑํ•˜์‹  ๋ฐฉ๋ฒ•๋Œ€๋กœ localStorage์— ์ €์žฅ์‹œ์ผœ์„œ XSS์— ์œ„ํ—˜์— ๋…ธ์ถœ๋˜์–ด๋„ ํƒˆ์ทจ๋ฅผ ๋‹นํ–ˆ์„๋•Œ๋Š” ์ด๋ฏธ token์ด ๋งŒ๋ฃŒ๋˜์–ด ์‚ฌ์šฉํ•  ์ˆ˜ ์—†์–ด์„œ ๋น„๊ต์  ์•ˆ์ „ํ•˜๋‹ค ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค.

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2021๋…„ 7์›” 24์ผ

ํ† ํฐ์„ ์ถ”์ฒœํ•˜์‹  ์ด์œ ๊ฐ€ "์ธ์ฆ ๊ด€๋ฌธ์„ 2๊ฐœ ๋งŒ๋“ค๊ธฐ ์œ„ํ•จ"์ด๋ผ๊ณ  ์œ„์— ์žˆ๋Š” ๋Œ€๋Œ“๊ธ€์—์„œ ์„ค๋ช… ์ฃผ์…จ๋Š”๋ฐ, ์ธ์ฆ ๊ด€๋ฌธ์ด 2๊ฐœ์ธ ๊ฒƒ์ด ์–ด๋–ค ์žฅ์ ์ด ์žˆ๋‚˜์š”? ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ์„ ๋‹ด๊ณ  ์žˆ๋Š” ์ฟ ํ‚ค๊ฐ€ CSRF ์ทจ์•ฝ์ ์— ๋…ธ์ถœ๋œ๋‹ค๋ฉด ๊ด€๋ฌธ์ด 1๊ฐœ์ด๊ฑด, 2๊ฐœ์ด๊ฑด ์œ„ํ—˜์— ๋…ธ์ถœ๋˜๋Š” ๊ฑด ๋˜‘๊ฐ™์ง€ ์•Š์„๊นŒ์š”?

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2021๋…„ 7์›” 30์ผ

onSilentRefresh = () => {
axios.post('/silent-refresh', data)
.then(onLoginSuccess)
.catch(error => {
// ... ๋กœ๊ทธ์ธ ์‹คํŒจ ์ฒ˜๋ฆฌ
});
}

์ด๋ถ€๋ถ„์—์„œ ๋‘๋ฒˆ์งธ์ค„์— ์žˆ๋Š” data๋Š” ์–ด๋–ค ๊ฒƒ์„ ๋งํ•˜๋Š”๊ฑด๊ฐ€์š”?? ์˜คํƒ€์ธ๊ฐ€์š”??

3๊ฐœ์˜ ๋‹ต๊ธ€

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2021๋…„ 9์›” 24์ผ

์ดํฌ์ŠคํŠธ ๋ณด๊ธฐ์ด์ „ ์ฐธ๊ณ ์ž๋ฃŒ ๋‹ค๋ณด์•˜์ง€๋งŒ,
์šฐ์—ฐํžˆ ๋“ค์–ด์˜ค๊ฒŒ๋๋Š”๋ฐ, ๋„ˆ๋ฌด ์ž˜ ์ •๋ฆฌ๋˜์–ด์žˆ์–ด ์ดํฌ์ŠคํŠธ ํ•˜๋‚˜๋งŒ ๋ณด๊ฒŒ๋˜๋„ค์š” ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹ใ…‹
์ •๋ง์œ ์šฉํ•˜๊ฒŒ ๋ดค์Šต๋‹ˆ๋‹ค ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2021๋…„ 11์›” 3์ผ

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค ์–ด๋ ค์šด ๋‚ด์šฉ์ด์—ˆ๋Š”๋ฐ ์‰ฝ๊ฒŒ ์ดํ•ด๋ฌ์–ด์š”!

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2022๋…„ 1์›” 16์ผ

yaytomato๋‹˜ ๊ธ€ ๋•๋ถ„์— ์ด์ œ ์„œ์•ผ refresh token์„ ์™œ ์‚ฌ์šฉํ•˜๋Š”์ง€ ์ดํ•ด๊ฐ€ ์ œ๋Œ€๋กœ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋‹ค๋ฅธ ๋ณด์•ˆ ์ด์Šˆ๋„ ์ดํ•ด ์‰ฝ๊ฒŒ ์„ค๋ช…ํ•ด์ฃผ์‹œ๊ณ  ์ข‹์€ ๊ธ€ ์ •๋ง๋กœ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค~!๐Ÿ‘๐Ÿ‘๐Ÿ˜Š

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2022๋…„ 2์›” 16์ผ

๋ณด๋‹ค๋ณด๋‹ˆ OAuth ์„ค๋ช…์ธ ๊ฒƒ ๊ฐ™์€๋ฐ, OAuth ๋ผ๋Š” ํ‚ค์›Œ๋“œ๊ฐ€ ์ „ํ˜€ ์—†์–ด์„œ ๋‹นํ™ฉ ์ค‘ ์ž…๋‹ˆ๋‹ค... JWT์™€ OAuth ์˜ ๊ด€๊ณ„์— ๋Œ€ํ•ด์„œ๋„ ์งง๊ฒŒ๋‚˜๋งˆ ์•Œ๋ ค์ฃผ์‹œ๋ฉด ์ข‹์„ ๊ฒƒ ๊ฐ™์•„์š”

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2022๋…„ 3์›” 16์ผ

๋”ฐ๋ด‰ํ•˜๋‚˜ ๋“œ๋ฆฝ๋‹ˆ๋‹ค

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2022๋…„ 7์›” 22์ผ

๊ธ€ ์ž˜ ๋ดค์Šต๋‹ˆ๋‹คใ…!!! :)

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2022๋…„ 9์›” 2์ผ

์•ก์„ธ์Šค ํ† ํฐ์„ ์—ฐ์žฅํ•  ๋•Œ, onSilentRefresh ํ•จ์ˆ˜๋ฅผ ์‹คํ–‰์‹œํ‚ค๊ณ  ์ƒˆ๋กœ์šด refresh token๊ณผ access token์„ ๋ฆฌํ„ด๋ฐ›๋Š”๋‹ค๊ณ  ์ ์œผ์…จ๋Š”๋ฐ, refresh token์˜ ์กด์žฌ ์ด์œ ๊ฐ€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค.
๊ทธ๋ƒฅ access token๋งŒ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๋” ๊ฐ„๋‹จํ•œ ๊ฒƒ ์•„๋‹Œ๊ฐ€์š”?

1๊ฐœ์˜ ๋‹ต๊ธ€
comment-user-thumbnail
2022๋…„ 9์›” 19์ผ

์‚ฌ๋ž‘ํ•ฉ๋‹ˆ๋‹ค ๋งŽ์ด ๋ฐฐ์› ์–ด์š” ใ…œใ…œ

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2023๋…„ 3์›” 15์ผ

์–‘์งˆ์˜ ๊ธ€ ์ •๋ง ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค!!

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2023๋…„ 5์›” 17์ผ

์œ ์šฉํ•œ ์ •๋ณด ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

ํ•˜๋‚˜ ๊ถ๊ธˆํ•œ๊ฒŒ ์žˆ๋Š”๋ฐ accessToken์„ ๋กœ์ปฌ๋ณ€์ˆ˜ ์ฆ‰ ์•„๋ž˜์™€ ๊ฐ™์ด ์„ค์ •ํ•˜์‹ ๋‹ค๊ณ  ํ•˜์…จ๋Š”๋ฐ
axios.defaults.headers.common['Authorization'] = Bearer ${accessToken};

์ด ๋˜ํ•œ javascript๋กœ ์ ‘๊ทผ์ด ๊ฐ€๋Šฅํ•˜์—ฌ xss์— ์ทจ์•ฝํ•œ ๊ฒƒ์ด ์•„๋‹Œ์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค.

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2023๋…„ 5์›” 23์ผ

๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๋•๋ถ„์— JWT์™€ ๋ณด์•ˆ์— ๋Œ€ํ•ด ๋งŽ์ด ๋ฐฐ์›Œ๊ฐ‘๋‹ˆ๋‹ค!!!!
ํ˜น์‹œ ์ถœ์ฒ˜๋ฅผ ๋‚จ๊ธฐ๊ณ  ์ œ ๋ธ”๋กœ๊ทธ์— ๊ธ€์„ ์ข€ ๋‚จ๊ฒจ๋‘ฌ ๋ ๊นŒ์š”??

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2023๋…„ 5์›” 27์ผ

ํ˜น์‹œ ์‚ฌํŒŒ๋ฆฌ์—์„œ๋„ httponly option ์œผ๋กœ refreshToken์„ ์ฃผ๊ณ  ๋ฐ›๋Š”๊ฒŒ ๊ฐ€๋Šฅํ•œ๊ฐ€์š”? ๋งŒ์•ฝ ์„œ๋ฒ„ ๋„๋ฉ”์ธ๊ณผ ํด๋ผ์ด์–ธํŠธ ๋„๋ฉ”์ธ์ด ๋‹ค๋ฅธ ๊ฒฝ์šฐ์—๋„ ์œ„์™€ ๊ฐ™์€ ์ธ์ฆ๋ฐฉ์‹์ด ๊ฐ€๋Šฅํ•œ ๊ฒƒ์ธ์ง€ ๊ถ๊ธˆํ•ฉ๋‹ˆ๋‹ค

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ
comment-user-thumbnail
2024๋…„ 2์›” 25์ผ

์ข‹์€ ๊ธ€ ๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค. ๊ทธ๋Ÿฐ๋ฐ client๋Š” server๋กœ ์š”์ฒญ์„ ๋ณด๋‚ผ๋•Œ ํ•ญ์ƒ header์— cookie๋ฅผ ๋‹ด์•„ ๋ณด๋‚ด๋Š” ๊ฑธ๋กœ ์•Œ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. refresh token๋ฅผ ์“ฐ๋Š” ์ด์œ ๋Š” (access token์ด ๋งŒ๋ฃŒ๋˜์—ˆ๋‹ค๋Š” ์‹ ํ˜ธ๋ฅผ ๋ฐ›์„๋•Œ๋งŒ ๋ณด๋ƒ„์œผ๋กœ์„œ) ํ†ต์‹  ํšŸ์ˆ˜ ์ž์ฒด๋ฅผ ์ค„์—ฌ ํƒˆ์ทจ ๋‹นํ•  ์œ„ํ—˜์„ ์ค„์ด๊ธฐ ์œ„ํ•จ์ธ๋ฐ, refresh token์„ cookie์— ๋„ฃ์œผ๋ฉด ๋ชจ๋“  ์š”์ฒญ์— refresh token์ด ํฌํ•จ๋˜๋‹ˆ๊นŒ refresh token์˜ ์žฅ์ ์ด ์‚ฌ๋ผ์ง€๋Š” ๊ฒƒ ์•„๋‹Œ๊ฐ€์š”?

๊ถ๊ธˆํ•ด์„œ ๋ฌผ์–ด๋ด…๋‹ˆ๋‹ค...!

๋‹ต๊ธ€ ๋‹ฌ๊ธฐ