p r o j e c t

๐Ÿ’พ pre ์Šคํƒ์˜ค๋ฒ„ํ”Œ๋กœ์šฐ ํด๋ก  / JWT, ์–ด๋””์— ์ €์žฅํ• ๊นŒ?(feat. Axios interceptor)

hee.hee 2022. 8. 28. 00:17

 

 

๐Ÿ“‚ ์„œ๋ฒ„-ํด๋ผ์ด์–ธํŠธ ํ† ํฐ ์ธ์ฆ ๊ธฐ๋ณธ ๋กœ์ง

  • ์š”์ฒญ ์‹œ ์„œ๋ฒ„์—์„œ ํ—ค๋”์— access, refresh ํ† ํฐ์„ ๋‹ด์•„ ์‘๋‹ตํ•œ๋‹ค.
    (ex. set-cookie ํ—ค๋”์— refresh ํ† ํฐ์„, payload์— access ํ† ํฐ์„ ๋‹ด์•„ ์‘๋‹ตํ•œ๋‹ค)
  • ํด๋ผ์ด์–ธํŠธ๋Š” ์ด ํ† ํฐ๋“ค์„ ์ €์žฅํ•ด๋‘์—ˆ๋‹ค๊ฐ€ ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ access ํ† ํฐ์„ ๋ณด๋‚ธ๋‹ค.
  • access ํ† ํฐ์ด ๋งŒ๋ฃŒ๋˜๋ฉด ์„œ๋ฒ„์—์„œ ๋งŒ๋ฃŒ ์‚ฌ์ธ(401์—๋Ÿฌ์™€ ๋งŒ๋ฃŒ๋ฅผ ์•Œ๋ฆฌ๋Š” ๋ฉ”์„ธ์ง€)์„ ๋ณด๋‚ด๊ณ 
  • ํด๋ผ์ด์–ธํŠธ๋Š” ์ €์žฅํ•ด๋‘” refresh ํ† ํฐ์„ ํฌํ•จ์‹œ์ผœ ์„œ๋ฒ„์— ๋ณด๋‚ธ๋‹ค.
  • ์„œ๋ฒ„๋Š” refresh ํ† ํฐ์„ ํ™•์ธํ•˜๊ณ , ์ธ์ฆ๋˜๋ฉด ์ƒˆ๋กœ์šด access, refresh ํ† ํฐ์„ ์‘๋‹ต์œผ๋กœ ๋ณด๋‚ธ๋‹ค.
  • ํด๋ผ์ด์–ธํŠธ๋Š” ์ƒˆ๋กœ ๋ฐ›์€ ํ† ํฐ๋“ค๋กœ ๊ธฐ์กด ํ† ํฐ์„ ๊ฐฑ์‹ ํ•œ๋‹ค.
  • ์ดํ›„ ์š”์ฒญ์€ ๊ฐฑ์‹ ํ•œ ํ† ํฐ์„ ์‚ฌ์šฉํ•œ๋‹ค.

 

 


 

๐Ÿ“‚  ํ† ํฐ ์ €์žฅ๊ณผ ๊ด€๋ จ๋œ ๋ณด์•ˆ์— ๋Œ€ํ•œ ์งง์€ ์ง€์‹

XSS(Cross Site Scripting)

์•…์˜์ ์ธ js ์ฝ”๋“œ๋ฅผ ๊ณต๊ฒฉ ๋‹นํ•œ ํด๋ผ์ด์–ธํŠธ์˜ ๋ธŒ๋ผ์šฐ์ €์—์„œ ์‹คํ–‰์‹œํ‚ค๋Š” ๊ฒƒ์œผ๋กœ, ๋ธŒ๋ผ์šฐ์ €์— ์ €์žฅ๋œ ์ค‘์š”ํ•œ ์ •๋ณด๋ฅผ ํƒˆ์ทจํ•  ์ˆ˜ ์žˆ๋‹ค.

์›น ์ƒ์—์„œ ๊ฐ€์žฅ ๊ธฐ์ดˆ์ ์ธ ์ทจ์•ฝ์  ๊ณต๊ฒฉ ๋ฐฉ๋ฒ•์˜ ์ผ์ข…์ด๋‹ค.

 

CSRF(Cross Site Request Forgery)

request๋ฅผ ๊ฐ€๋กœ์ฑ„์„œ ๋ฐฑ์—”๋“œ ์„œ๋ฒ„์— ๋ณ€์กฐ๋œ request๋ฅผ ๋ณด๋‚ด ์•…์˜์ ์ธ ๋™์ž‘์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ณต๊ฒฉ(ํด๋ผ์ด์–ธํŠธ ์ •๋ณด ์ˆ˜์ •, ์—ด๋žŒ)

๊ณต๊ฒฉ ๊ณผ์ • ์˜ˆ์‹œ: ima, link๋ฅผ ํด๋ฆญํ•œ๋‹ค -> ๊ณต๊ฒฉ์ž๊ฐ€ ์˜๋„ํ•œ http request๊ฐ€ ์ „์†ก๋œ๋‹ค

 

 


 

 

๐Ÿ“‚ localStorage vs cookie

localStorage

์žฅ์ : CSRF ๊ณต๊ฒฉ์— ์•ˆ์ „

์ฟ ํ‚ค๋Š” ์ž๋™์œผ๋กœ request์— ๋‹ด๊ธฐ๋Š” ๋ฐ˜๋ฉด localStorage์˜ ํ† ํฐ์€ js ์ฝ”๋“œ์— ์˜ํ•ด ํ—ค๋”์— ๋‹ด๊ธด๋‹ค.

๋•Œ๋ฌธ์— XSS์— ์ทจ์•ฝํ•˜์ง€ ์•Š์€ ์ด์ƒ ๊ณต๊ฒฉ์ž๊ฐ€ ํด๋ผ์ด์–ธํŠธ์ธ ์ฒ™ request๋ฅผ ๋ณด๋‚ด๊ธฐ ์–ด๋ ต๋‹ค.

 

๋‹จ์ : XSS์— ์ทจ์•ฝ

๊ณต๊ฒฉ์ž๊ฐ€ localStorage์— ์ ‘๊ทผํ•˜๋Š” ์ฝ”๋“œ๋งŒ ์ฃผ์ž…ํ•˜๋ฉด ํƒˆ์ทจ๊ฐ€ ๊ฐ€๋Šฅํ•˜๋‹ค.

 

cookie

์žฅ์  1: localStorage์— ๋น„ํ•ด XSS ๊ณต๊ฒฉ์— ์•ˆ์ „

์ฟ ํ‚ค์˜ httpOnly ์˜ต์…˜์„ ์‚ฌ์šฉํ•˜๋ฉด JS์—์„œ ์ฟ ํ‚ค์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋‹ค.

์™„์ „ํžˆ ์•ˆ์ „ํ•œ ๊ฒƒ์€ ์•„๋‹ˆ๋‹ค. ์ž๋™์œผ๋กœ request์— ์ฟ ํ‚ค๊ฐ€ ์‹ค๋ฆฌ๋‹ˆ ์‚ฌ์šฉ์ž์˜ ์ปดํ“จํ„ฐ์—์„œ ์š”์ฒญ์„ ์œ„์กฐํ•  ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

XSS๊ฐ€ ์„ฑ๊ณตํ•˜๋ฉด httpOnly cookie๋„ ์•ˆ์ „ํ•˜์ง€ ์•Š๋‹ค.

 

๋‹จ์ : CSRF์— ์ทจ์•ฝ

์ž๋™์œผ๋กœ http request์— ๋‹ด๊ฒจ์ง€๊ธฐ ๋•Œ๋ฌธ์— ๊ณต๊ฒฉ์ž๊ฐ€ request url์„ ์•ˆ๋‹ค๋ฉด ์‚ฌ์šฉ์ž๊ฐ€ link, img๋ฅผ ํด๋ฆญํ•˜๋„๋ก ์œ ๋„ํ•˜์—ฌ request๋ฅผ ์œ„์กฐํ•  ์ˆ˜ ์žˆ๋‹ค. ์ตœ๊ทผ์—๋Š” ์ฟ ํ‚ค์˜ CSRF ์ทจ์•ฝ์ ์„ ๋ง‰๊ธฐ ์œ„ํ•ด request์— ์ž๋™์œผ๋กœ ์ฟ ํ‚ค๊ฐ€ ์‹ค๋ฆฌ์ง€ ์•Š๋Š” ๊ฒฝ์šฐ๋„ ์žˆ๋‹ค.

request์— ์ฟ ํ‚ค๊ฐ€ ์‹ค๋ฆฌ์ง€ ์•Š๋Š” ๊ฒฝ์šฐ์— ๋Œ€ํ•ด ์ •๋ฆฌํ•œ ๊ธ€

 

 


 

๐Ÿ“‚ ๊ทธ๋ž˜์„œ, ํ”„๋ก ํŠธ์—”๋“œ์—์„œ ํ† ํฐ์„ ์–ด๋””์— ์ €์žฅํ•˜์ง€?

 

MDN์€ Modern APIs์˜ ์ข…๋ฅ˜์ธ ์›น ์Šคํ† ๋ฆฌ์ง€ API (localStorage์™€ sessionStorage) ์™€ IndexedDB๋ฅผ ์‚ฌ์šฉํ•  ๊ฒƒ์„ ๊ถŒ์žฅํ•œ๋‹ค.

๊ณผ๊ฑฐ์—” ํด๋ผ์ด์–ธํŠธ ์ธก์— ์ •๋ณด๋ฅผ ์ €์žฅํ•  ๋•Œ ์ฟ ํ‚ค๋ฅผ ์ฃผ๋กœ ์‚ฌ์šฉํ•˜๊ณค ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ฟ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒŒ ๋ฐ์ดํ„ฐ๋ฅผ ํด๋ผ์ด์–ธํŠธ ์ธก์— ์ €์žฅํ•  ์ˆ˜ ์žˆ๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์ด์—ˆ์„ ๋•Œ๋Š” ์ด ๋ฐฉ๋ฒ•์ด ํƒ€๋‹นํ–ˆ์ง€๋งŒ, ์ง€๊ธˆ์€ modern storage APIs๋ฅผ ์‚ฌ์šฉํ•ด ์ •๋ณด๋ฅผ ์ €์žฅํ•˜๋Š” ๊ฑธ ๊ถŒ์žฅํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋“  ์š”์ฒญ๋งˆ๋‹ค ์ฟ ํ‚ค๊ฐ€ ํ•จ๊ป˜ ์ „์†ก๋˜๊ธฐ ๋•Œ๋ฌธ์—, (ํŠนํžˆ mobile data connections์—์„œ) ์„ฑ๋Šฅ์ด ๋–จ์–ด์ง€๋Š” ์›์ธ์ด ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ •๋ณด๋ฅผ ํด๋ผ์ด์–ธํŠธ ์ธก์— ์ €์žฅํ•˜๋ ค๋ฉด Modern APIs์˜ ์ข…๋ฅ˜์ธ ์›น ์Šคํ† ๋ฆฌ์ง€ API (localStorage์™€ sessionStorage) ์™€ IndexedDB๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋ฉ๋‹ˆ๋‹ค.
์ถœ์ฒ˜: MDN HTTP ์ฟ ํ‚ค

+ IndexedDB: ์›น ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ œ๊ณตํ•˜๋Š” ์›น ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ํด๋ผ์ด์–ธํŠธ ์ธก ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค

localStorage๋Š” XSS์— ์ทจ์•ฝํ•˜์ง€๋งŒ CSRF์— ์•ˆ์ „ํ•˜๋‹ค.

๋ฐ˜๋ฉด cookie๋Š” localStorage์— ๋น„ํ•ด XSS ๊ณต๊ฒฉ์— ์•ˆ์ „ํ•˜์ง€๋งŒ '์™„์ „ํžˆ' ์•ˆ์ „ํ•˜์ง€๋Š” ์•Š๊ณ , CSRF์— ์ทจ์•ฝํ•˜๋‹ค.

์ด๋Ÿฌํ•œ ์ด์œ ์—์„œ localStorage๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค.

 

 

์•„๋ž˜๋Š” ๋‚ด๊ฐ€ ํ† ํฐ์„ ์ €์žฅํ•˜๊ธฐ ์œ„ํ•ด ์ฝ์—ˆ๋˜ ๋ธ”๋กœ๊ทธ ๊ธ€๋“ค์ด๋‹ค.

Axios๋ฅผ ์ด์šฉํ•ด์„œ Access ํ† ํฐ๊ณผ Refresh ํ† ํฐ์„ ๊ฐฑ์‹ ํ•˜๋Š” ๋ฐฉ๋ฒ•

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

6) React - JWT๋ฅผ ์ด์šฉํ•œ ๋กœ๊ทธ์ธ ์ธ์ฆ - 2๋ถ€

 

 


 

์กฐ์‚ฌ ์ค‘์— ๋ณด์•ˆ์„ ์œ„ํ•ด์„œ๋Š” refresh token์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์ข‹๋‹ค๋Š” ๊ฒฐ๋ก ์„ ์–ป์—ˆ๋‹ค.
ํ•˜์ง€๋งŒ... ๊ฒฐ๋ก ๋ถ€ํ„ฐ ๋งํ•˜์ž๋ฉด ์šฐ๋ฆฌ ํŒ€์€ ๋ฐฑ์—”๋“œ ์ธก์—์„œ refresh token -> access token ๊ฐฑ์‹  ์˜ค๋ฅ˜๋ฅผ ํ•ด๊ฒฐํ•˜์ง€ ๋ชปํ–ˆ๋‹ค.
์–ด์ฉ” ๋•Œ๋Š” ํ† ํฐ ๊ฐฑ์‹ ์ด ์„ฑ๊ณตํ•˜๊ณ , ์–ด์ฉ” ๋•Œ๋Š” ์•ˆ๋˜๋Š” ์ƒํ™ฉ์˜ ์—ฐ์†์ด์—ˆ๋‹ค.
๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž ๋ถ„์ด ํ•œ ๋ช…์ด๋‹ค ๋ณด๋‹ˆ ๋‹ค๋ฅธ ๊ตฌํ˜„ ์‚ฌํ•ญ๋„ ๋งŽ์ด ๋‚จ์€ ์ƒํ™ฉ์—์„œ ํ•„์ˆ˜ ๊ตฌํ˜„์ด ์•„๋‹Œ ํ† ํฐ์—๋งŒ ์ง‘์ค‘ํ•  ์ˆ˜๊ฐ€ ์—†์–ด์„œ
refresh ํ† ํฐ์€ main ํ”„๋กœ์ ํŠธ์—์„œ ๊ตฌํ˜„๊ธฐ๋กœ ํ–ˆ๋‹ค.
+ main ํ”„๋กœ์ ํŠธ์—์„œ ๋งŒ๋‚œ ๋ฉ˜ํ† ๋‹˜์€ refresh token์€ ํ•„์ˆ˜๊ฐ€ ์•„๋‹ˆ๋‹ˆ access token ๋งŒ์œผ๋กœ๋„ ์ถฉ๋ถ„ํ•˜๋‹ค๊ณ  ํ•˜์…จ๋‹ค. 

๋‹น์‹œ์—๋Š” refresh token ์„ ๊ตฌํ˜„ํ•˜๊ธฐ ์œ„ํ•ด ์ฒ˜์Œ์œผ๋กœ axios interceptor๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค.

 

 

๐Ÿ“‚ axios interceptor

ํ† ํฐ์ด ๋งŒ๋ฃŒ๋œ ๊ฒฝ์šฐ์— ์–ด๋–ค ์ผ์ด ์ผ์–ด๋‚˜๋Š”์ง€, ํ”„๋ก ํŠธ๋กœ ์–ด๋–ค ์‘๋‹ต์ด ์˜ค๋Š”์ง€,

๊ทธ๋Ÿผ ํ”„๋ก ํŠธ์—์„œ๋Š” ์–ด๋–ค ํ˜•ํƒœ๋กœ refreshํ† ํฐ์„ ์ „๋‹ฌํ•ด์•ผํ•˜๋Š”์ง€ ๋ฐฑ์—”๋“œ๋ถ„๋“ค๋„ ์šฐ๋ฆฌ๋„ ์ž˜๋ชฐ๋ผ์„œ ์ •ํ™•ํžˆ ๋ชจ๋ฅด๋Š” ์ƒํƒœ์—ฌ์„œ ํž˜๋“ค์—ˆ๋‹ค.

๊ทธ๋ž˜์„œ ์„œ๋ฒ„์—์„œ header์— ๋‘ ํ† ํฐ์„ ๋„˜๊ฒจ์ค€๋‹ค๋Š” ๊ฒƒ, ๋งŒ๋ฃŒ ์‹œ ๋‹ค์‹œ ์š”์ฒญ์„ ๋ณด๋‚ธ๋‹ค๋Š” ๊ฒƒ๋งŒ ์ „์ œ๋กœ ์กฐ์‚ฌ ํ–ˆ๊ณ ,

ํด๋ผ์ด์–ธํŠธ์—์„œ ์ตœ๋Œ€ํ•œ ํ•ด๊ฒฐ์„ ํ•˜๋ ค๊ณ  ๋…ธ๋ ฅ ํ•˜๋‹ค๋ณด๋‹ˆ,

"๋งŒ๋ฃŒ ์‘๋‹ต(์—๋Ÿฌ)๊ฐ€ ์˜ค๋ฉด catch ์•ˆ์—์„œ refresh ํ† ํฐ์„ ๋‹ค์‹œ ๋ณด๋‚ด๋Š”" ์ฝ”๋“œ๋ฅผ ์งœ๋ ค๊ณ  ํ–ˆ๋‹ค.

ํ•˜์ง€๋งŒ catch ์•ˆ์—์„œ ๋‹ค์‹œ http ์š”์ฒญ์ด ๊ฐ€๋Šฅํ•œ์ง€ ํ™•์ธํ•  ์ˆ˜๊ฐ€ ์—†์—ˆ๋‹ค.

๊ทธ๋ž˜๋„ ๊ทธ err์— ๋‹ด๊ธด ๋งŒ๋ฃŒ ์—ฌ๋ถ€๋ฅผ ์ฝ์–ด์•ผ๋งŒ refresh ํ† ํฐ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ์œผ๋‹ˆ,

์—ฌ๋Ÿฌ ๋ฐฉ๋ฒ•์„ ํƒ์ƒ‰ํ•˜๋˜ ์ค‘, axios์˜ interceptor ๋ผ๋Š” ๊ฒƒ์„ ๋ฐœ๊ฒฌํ–ˆ๋‹ค.

 

interceptor๋Š” axios์˜ ๊ธฐ๋Šฅ ์ค‘ ํ•˜๋‚˜๋‹ค. ์š”์ฒญ๊ณผ ์‘๋‹ต์„ ์ค‘๊ฐ„์— ์ธํ„ฐ์…‰ํŠธ~

๊ฐ€๋กœ์ฑ„์„œ ๋ฌด์–ธ๊ฐ€ ์‚ด์„ ๋ถ™์ธ ๋‹ค์Œ์— ๋ณด๋‚ธ๋‹ค๊ณ  ์ƒ๊ฐํ•˜๋ฉด ์‰ฝ๋‹ค.

 

๋ฌผ๋ก  ์šฐ๋ฆฌ๊ฐ€ ์›ํ–ˆ๋˜, http ์š”์ฒญ๋„ ๊ฐ€๋Šฅํ•˜๋‹ค! ์„ค์ •์ด ๊ทธ๋ฆฌ ์–ด๋ ต์ง€ ์•Š๋‹ค.

ํ•˜์ง€๋งŒ ์šฐ๋ฆฌ๋Š” axios ์ธ์Šคํ„ด์Šค์— ๊ธฐ๋ณธ ์„ค์ • ํ•  ํ•„์š”๋ฅผ ๋ชป๋А๊ปด์„œ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค๊ณ ์‹ถ์ง€ ์•Š์•˜๊ณ ,

์š”์ฒญํ•  ๋•Œ๋Š” interceptor ๊ธฐ๋Šฅ์ด ํ•„์š”ํ•˜์ง€ ์•Š์•˜๋‹ค. ์šฐ๋ฆฌ๊ฐ€ ํ•„์š”ํ•œ ๊ฑด ๋”ฑ ํ•˜๋‚˜.

"์‘๋‹ต ์‹œ ํ† ํฐ ๋งŒ๋ฃŒ ์—๋Ÿฌ๊ฐ€ ์ƒ๊ธฐ๋ฉด intercept ํ•ด์„œ ํ† ํฐ์„ ๊ฐฑ์‹ ํ•˜๊ณ , ์ƒˆ๋กœ์šด ํ† ํฐ์œผ๋กœ ์ด์ „์˜ ์š”์ฒญ์„ ๋‹ค์‹œ ๋ณด๋‚ธ๋‹ค" ์ด๊ฑฐ์˜€๋‹ค.

 

 

๊ทธ๋ž˜์„œ ์ด๋Ÿฐ ๋กœ์ง์œผ๋กœ ๊ตฌํ˜„ ํ–ˆ๋‹ค.

 

๊ตฌํ˜„ ์ค‘๊ฐ„์— ๊ธฐ๋กํ–ˆ๋˜ ๊ฒƒ๋“ค.

์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ, ์„œ๋กœ์˜ ์‚ฌ์ •์„ ๋ชจ๋ฅด๋‹ˆ ํ•˜๋‚˜๋ผ๋„ ๊ณ„์† ๊ณต์œ ํ•˜๋ ค๊ณ  ๋…ธ๋ ฅํ–ˆ๋‹ค.

 

 


 

๐Ÿ“‚ axios์˜ ๊ธฐ๋Šฅ๋“ค

  • ์•Œ์•„์„œ JSON ๋ฐ์ดํ„ฐ๋กœ ๋ณ€ํ™˜ ํ•ด์ค€๋‹ค.
  • ํ—ค๋”, ์š”์ฒญ ์ฃผ์†Œ ๋“ฑ ๊ธฐ๋ณธ ์„ค์ •์„ ํ•œ ์ธ์Šคํ„ด์Šค๋ฅผ ๋งŒ๋“ค ์ˆ˜ ์žˆ๋‹ค.
  • ์š”์ฒญ ํ—ค๋”์— ๊ธฐ๋ณธ ๊ฐ’์„ ์„ค์ •ํ•  ์ˆ˜ ์žˆ๋‹ค.

 


 

 

์ฐธ๊ณ ํ•œ ๊ธ€