Project

JWT ํ† ํฐ ์–ด๋””์— ์ €์žฅํ•˜๋Š”๊ฒŒ ์ข‹์„๊นŒ?

๐Ÿถzio 2024. 12. 16. 00:05

 

 

ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด์„œ JWT ํ† ํฐ์„ ์–ด๋””์— ์ €์žฅํ•ด์•ผ ์ข‹์„๊นŒ ์˜๋ฌธ์ด ๋“ค์—ˆ๋‹ค.๐Ÿค”

์šฐ์„  ๋‚ด๊ฐ€ ๊ฒฝํ—˜ํ•œ ํ”„๋กœ์ ํŠธ์—์„œ ํ† ํฐ์„ ์ €์žฅํ•œ ์œ„์น˜๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™๋‹ค.

 

  1. access token, refresh token ๋ชจ๋‘ ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅ
  2. access token์€ ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅ, refresh token์€ ์ฟ ํ‚ค์— ์ €์žฅ
  3. access token, refresh token ๋ชจ๋‘ ์ฟ ํ‚ค์— ์ €์žฅ

 

๊ฐœ๋ฐœ ๋‹น์‹œ์—๋Š” ๋‹จ์ˆœํžˆ (์ฝ”๋“œ์งœ๊ธฐ)ํŽธํ•ด์„œ ์œ„์™€ ๊ฐ™์ด ์„ค์ •ํ–ˆ์ง€๋งŒ, ์ง€๊ธˆ ์ƒ๊ฐํ•ด๋ณด๋ฉด ๋ณด์•ˆ์— ์ „ํ˜€ ์‹ ๊ฒฝ์“ฐ์ง€ ์•Š์•˜๋˜ ๊ฒƒ ๊ฐ™๋‹ค. ํŠนํžˆ ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— ํ† ํฐ์„ ์ €์žฅํ–ˆ๋˜ ๊ฒƒ์€ ์ •๋ง ๋ฐ˜์„ฑํ•œ๋‹ค.

๊ทธ๋ ‡๋‹ค๋ฉด ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— JWTํ† ํฐ์„ ์ €์žฅํ•˜๋ฉด ์•ˆ๋˜๋Š” ์ด์œ ์™€ ํ† ํฐ์„ ์–ด๋””์— ์ €์žฅํ•˜๋ฉด ์ข‹์„์ง€ ์ •๋ฆฌํ•ด ๋ณด์•˜๋‹ค.

 

 


 

 

 

localStorage์— ํ† ํฐ์„ ์ €์žฅํ•˜๋ฉด ์•ˆ๋˜๋Š” ์ด์œ 


1. XSS(Cross-Site Scripting) ๊ณต๊ฒฉ์— ์ทจ์•ฝ

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

๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€๋Š” ํด๋ผ์ด์–ธํŠธ ์ธก ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ์—์„œ ์ ‘๊ทผ ๊ฐ€๋Šฅํ•˜๋‹ค. ๋งŒ์•ฝ ๊ณต๊ฒฉ์ž๊ฐ€ XSS๋ฅผ ํ†ตํ•ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๋‚ด์—์„œ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค๋ฉด, ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€์— ์ €์žฅ๋œ ํ† ํฐ์„ ํ›”์น  ์ˆ˜ ์žˆ๋‹ค.

 

 

 

2. ์„ธ์…˜ ๊ด€๋ฆฌ์˜ ์–ด๋ ค์›€

๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€๋Š” ๋ธŒ๋ผ์šฐ์ € ์„ธ์…˜์ด ์ข…๋ฃŒ๋˜์–ด๋„ ๋ฐ์ดํ„ฐ๊ฐ€ ๋‚จ์•„ ์žˆ๊ธฐ ๋•Œ๋ฌธ์—, ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์•„์›ƒ์„ ํ•˜๊ฑฐ๋‚˜ ์‚ฌ์ดํŠธ๋ฅผ ๋‹ซ์•„๋„ ํ† ํฐ์ด ๋‚จ์•„ ์žˆ์„ ์ˆ˜ ์žˆ๋‹ค.

๋งŒ์•ฝ ๋กœ๊ทธ์•„์›ƒ ์‹œ ๋กœ์ปฌ์Šคํ† ๋ฆฌ์ง€ ํ† ํฐ์„ ์‚ญ์ œํ•˜๋Š” ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•ด๋„, ๋กœ๊ทธ์ธ ์ƒํƒœ ์ดํ›„ ์ปดํ“จํ„ฐ๊ฐ€ ๊ฐ‘์ž‘์Šค๋Ÿฝ๊ฒŒ ๊บผ์ง€๋Š” ์ผ์ด ๋ฐœ์ƒํ•œ๋‹ค๋ฉด ํ† ํฐ์ด ๊ณ„์† ๋‚จ์•„์žˆ๊ฒŒ ๋œ๋‹ค.

 

 

 

 

๊ทธ๋ ‡๋‹ค๋ฉด JWTํ† ํฐ์„ ์–ด๋””์— ์ €์žฅํ•˜๋Š” ๊ฒƒ์ด ์ข‹์„๊นŒ?


1. Cookie

HttpOnly + Secure ์„ค์ •์ด ๋œ ์ฟ ํ‚ค์— ์ €์žฅํ•˜๋Š” ๊ฒƒ์ด ๊ฐ€์žฅ ์•ˆ์ „ํ•˜๋‹ค. ์ฟ ํ‚ค๋Š” ๋ธŒ๋ผ์šฐ์ €์—์„œ ๊ด€๋ฆฌ๋˜๋ฏ€๋กœ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ์ง์ ‘ ์ ‘๊ทผํ•  ์ˆ˜ ์—†๊ณ , XSS ๊ณต๊ฒฉ์— ๋Œ€ํ•œ ์•ˆ์ „์„ฑ์„ ๋†’์ผ ์ˆ˜ ์žˆ๋‹ค.

  • HttpOnly ์†์„ฑ : ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ ์ ‘๊ทผํ•  ์ˆ˜ ์—†์œผ๋ฏ€๋กœ XSS ๊ณต๊ฒฉ์„ ๋ฐฉ์–ดํ•œ๋‹ค.
  • Secure ์†์„ฑ : HTTPS ํ™˜๊ฒฝ์—์„œ๋งŒ ์ฟ ํ‚ค ์ „์†ก์ด ๊ฐ€๋Šฅํ•˜๋‹ค
  • SameSite ์†์„ฑ : CSRF ๊ณต๊ฒฉ ๋ฐฉ์–ด์— ๋„์›€์„ ์ค€๋‹ค.
  • ์ž๋™์œผ๋กœ ์š”์ฒญ ํ—ค๋”์— ํฌํ•จ๋˜์–ด ์ธ์ฆ์ด ๊ฐ„ํŽธํ•˜๋‹ค.
  • SetCookie๋ฅผ ์‚ฌ์šฉํ•ด ํด๋ผ์ด์–ธํŠธ์— ์ „๋‹ฌํ•˜๋ฉด ์ž๋™์œผ๋กœ ์ €์žฅ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์ถ”๊ฐ€ ์ฝ”๋“œ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š๋‹ค.
Set-Cookie: accessToken=abc123; HttpOnly; Secure; SameSite=Strict; Max-Age=3600

CSRF(Cross-Site Request Forgery)๋ž€ ์‹ ๋ขฐํ•  ์ˆ˜ ์žˆ๋Š” ์‚ฌ์šฉ์ž๋ฅผ ์‚ฌ์นญํ•ด ์›น ์‚ฌ์ดํŠธ์— ์›ํ•˜์ง€ ์•Š์€ ๋ช…๋ น์„ ๋ณด๋‚ด๋Š” ๊ณต๊ฒฉ์ด๋‹ค.
-MDN ๋ฌธ์„œ

 

 

 

2. Refresh Token๊ณผ Access Token ๋ถ„๋ฆฌ

  • Access Token : CSRF ๊ณต๊ฒฉ์— ์ทจ์•ฝํ•˜์ง€ ์•Š๋„๋ก ๋ฉ”๋ชจ๋ฆฌ์— ์ €์žฅํ•œ๋‹ค. ์—ฌ๊ธฐ์„œ ๋ฉ”๋ชจ๋ฆฌ๋Š” ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๋ณ€์ˆ˜๋‚˜ ๊ฐ์ฒด๋ฅผ ์˜๋ฏธํ•œ๋‹ค.(์ „์—ญ ๋ณ€์ˆ˜๋Š” ํ”ผํ•ด์•ผ ํ•œ๋‹ค.) ๊ด€๋ฆฌํ•˜๊ธฐ ์‰ฌ์šด zustand๋‚˜ redux๋ฅผ ์ถ”์ฒœํ•œ๋‹ค.
  • ์ƒˆ๋กœ ๊ณ ์นจ ์‹œ Access Token์„ ์ƒˆ๋กœ ๋ฐ›์•„์•ผ ํ•˜๋Š” ๋‹จ์ ์ด ์žˆ๋‹ค.
  • Refresh Token : ์œ„์—์„œ ์„ค๋ช…ํ•œ HttpOnly + Secure ์ฟ ํ‚ค์— ์ €์žฅํ•œ๋‹ค. ๋˜๋Š” DB(Redis)์— ์ €์žฅํ•˜๋Š” ๋ฐฉ์‹๋„ ์žˆ๋‹ค.
  • ์ด ๊ฒฝ์šฐ ์•ก์„ธ์Šค ํ† ํฐ์ด ํ•„์š”ํ•˜์ง€ ์•Š์€ ์š”์ฒญ์— ํ† ํฐ์ด ์ „์†ก๋˜๋Š” ๊ฒƒ์„ ๋ง‰์„ ์ˆ˜ ์žˆ๋‹ค.

refresh token์„ db์— ์ €์žฅํ•˜๋Š” ๊ฒฝ์šฐ

 

 

 


 

 

 

JWT ํ† ํฐ์„ ๋ชจ๋‘ Cookie์— ์ €์žฅํ–ˆ์„ ๋•Œ, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๊ฐ€ ์ ‘๊ทผ ํ•  ์ˆ˜ ์—†๋‹ค. (HttpOnly ์†์„ฑ)

 

ํ”„๋กœ์ ํŠธ์—์„œ access token์˜ payload์— ์œ ์ €Id๋ฅผ ๋„ฃ๊ณ , ํ† ํฐ์„ ๋””์ฝ”๋”ฉํ•ด ์œ ์ €Id๋ฅผ ์‚ฌ์šฉํ•˜๋ ค๊ณ  ํ–ˆ๋˜ ์ ์ด ์žˆ์—ˆ๋‹ค. ์ด Id๋ฅผ ๊ฒŒ์‹œ๊ธ€ ์‹๋ณ„์— ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์—ˆ์ง€๋งŒ, HttpOnly ์†์„ฑ์„ ์„ค์ •ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ์ฝ”๋“œ๊ฐ€ ์ ‘๊ทผํ•  ์ˆ˜ ์—†์–ด ์• ๋จน์—ˆ๋˜ ๊ฒฝํ—˜์ด ์žˆ๋‹ค.๐Ÿ˜‚

 

์ด๋•Œ๋Š” ๊ทธ๋ƒฅ API๋กœ ์œ ์ € ์ •๋ณด๋ฅผ ๋ฐ›์œผ๋ฉด ๋œ๋‹ค. ์œ ์ € ์ •๋ณด๋ฅผ ์š”์ฒญํ•˜๋Š” API๋ฅผ ๋ณด๋‚ด๋ฉด(๋กœ๊ทธ์ธ ํ›„ access token์ด cookie์— ์ €์žฅ๋˜์–ด ์žˆ๋‹ค๊ณ  ๊ฐ€์ •) ์š”์ฒญ ํ—ค๋”์— ์ฟ ํ‚ค๊ฐ€ ํฌํ•จ๋˜๊ณ , ์„œ๋ฒ„์—์„œ๋Š” ํ† ํฐ์„ ๋ฐ›์•„ ๋””์ฝ”๋”ฉํ•œ๋‹ค. ๊ทธ๋ฆฌ๊ณ  payload์— ์žˆ๋Š” ์œ ์ €Id๋ฅผ ๊ฐ€์ง€๊ณ  ์š”์ฒญ์„ ๋ณด๋‚ธ ์‚ฌ์šฉ์ž๊ฐ€ ๋ˆ„๊ตฌ์ธ์ง€ ํŒ๋‹จํ•˜๋Š” ๊ฒƒ์ด๋‹ค.

 

ํ† ํฐ ๋””์ฝ”๋”ฉ์„ ๊ผญ ํด๋ผ์ด์–ธํŠธ์—์„œ ํ•ด์•ผํ•œ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋„ˆ๋ฌด ์ปธ๋˜ ๊ฒƒ ๊ฐ™๋‹ค.