์ƒ์„ธ ์ปจํ…์ธ 

๋ณธ๋ฌธ ์ œ๋ชฉ

[๋„คํŠธ์›Œํฌ] ์ฟ ํ‚ค ๋ฐฉ์‹๊ณผ ์„ธ์…˜ ๋ฐฉ์‹์„ ๊ณ ๋ฏผํ•˜๋Š” ์ด์œ  + ๋ธŒ๋ผ์šฐ์ € ๊ฐ„ ์ฟ ํ‚ค ๊ณต์œ 

CS/๋„คํŠธ์›Œํฌ๐Ÿ•Š

by :ํ•ดํ”ผ๋ž˜๋น—๐Ÿพ 2025. 7. 19. 11:25

๋ณธ๋ฌธ

์ฟ ํ‚ค ๋ฐฉ์‹๊ณผ ์„ธ์…˜ ๋ฐฉ์‹์„ ๊ณ ๋ฏผํ•˜๋Š” ์ด์œ  

์ฟ ํ‚ค ๋ฐฉ์‹

- ํด๋ผ์ด์–ธํŠธ์— ์ €์žฅ๋˜๋ฏ€๋กœ ์ƒ๋Œ€์ ์œผ๋กœ ์ทจ์•ฝํ•จ

- ์ €์žฅ ์œ„์น˜ : ํด๋ผ์ด์–ธํŠธ (๋ธŒ๋ผ์šฐ์ €)

- ์šฉ๋Ÿ‰ ์ œํ•œ : ์•ฝ 4KB

- ํ™•์žฅ์„ฑ : ์„œ๋ฒ„ ๋ฌด๊ด€(ํด๋ผ์ด์–ธํŠธ ์ €์žฅ) -> ํ™•์žฅ์„ฑ ์ข‹์Œ

- ์†๋„ : ์„œ๋ฒ„ ๋ถ€๋‹ด ์ ๊ณ , ๋น ๋ฆ„ 

- ์„ธ์…˜ ์œ ์ง€ : ๋ธŒ๋ผ์šฐ์ €์— ์ €์žฅ๋˜๋ฏ€๋กœ ์˜ค๋ž˜ ์œ ์ง€ ๊ฐ€๋Šฅ

- ์‹ค์ œ ํ™œ์šฉ : JWT ๊ธฐ๋ฐ˜ ํ† ํฐ ์ธ์ฆ ๋“ฑ 

 

์„ธ์…˜ ๋ฐฉ์‹ 

- ์„œ๋ฒ„์— ์ €์žฅ๋˜์–ด ๋ณด์•ˆ์„ฑ์ด ๋†’์Œ

- ์ €์žฅ์œ„์น˜ : ์„œ๋ฒ„ 

- ์šฉ๋Ÿ‰ ์ œํ•œ : ์„œ๋ฒ„ ๋ฉ”๋ชจ๋ฆฌ๋‚˜ ์ €์žฅ์†Œ ์šฉ๋Ÿ‰๋งŒํผ

- ํ™•์žฅ์„ฑ : ์„œ๋ฒ„ ์ €์žฅ -> ์„œ๋ฒ„ ๊ฐ„ ์„ธ์…˜ ๊ณต์œ  ํ•„์š” 

- ์†๋„ : ์„œ๋ฒ„ ๋ฆฌ์†Œ์Šค ์‚ฌ์šฉ, ๋А๋ฆด ์ˆ˜ ์žˆ์Œ 

- ์„ธ์…˜ ์œ ์ง€ : ์ผ๋ฐ˜์ ์œผ๋กœ ์ผ์ • ์‹œ๊ฐ„ ํ›„ ๋งŒ๋ฃŒ๋จ

- ์‹ค์ œ ํ™œ์šฉ : ๋กœ๊ทธ์ธ ์ƒํƒœ ์œ ์ง€ ๋“ฑ

 

์ง„์งœ ์ค‘์š”ํ•˜๊ฒŒ ๊ณ ๋ คํ•ด์•ผ ํ•˜๋Š” ๋ถ€๋ถ„์€ 

1. ๋กœ๊ทธ์ธ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•ด์•ผ ํ•˜๋Š” ์‚ฌ์šฉ์ž ์ˆ˜๊ฐ€ ๋งŽ์€๊ฐ€ 2. ๋ณด์•ˆ์ด ์ค‘์š”ํ•œ๊ฐ€ 2๊ฐ€์ง€ ๊ฒฝ์šฐ์ธ ๊ฒƒ ๊ฐ™๋‹ค. 

 


 

๋™์‹œ ๋กœ๊ทธ์ธ ํ—ˆ์šฉ ์—ฌ๋ถ€์— ๋”ฐ๋ฅธ ํ† ํฐ ๊ด€๋ฆฌ ๋ฐฉ์‹ : Token๊ธฐ๋ฐ˜ ์„ธ์…˜์„ ์‚ฌ์šฉํ•˜๊ณ  ์‹ถ์Œ

- Token๊ธฐ๋ฐ˜ ์„ธ์…˜ ๋ฐฉ์‹ : accessToken์€ statelessํ•˜๊ฒŒ, refreshToken์€ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅํ•ด๋‘๊ณ  ์‚ฌ์šฉํ•˜๋Š” ๋ฐฉ์‹

 

ํ† ํฐ ๋ฐฉ์‹์œผ๋กœ ์ธ์ฆ/์ธ๊ฐ€๋ฅผ ์ฒ˜๋ฆฌํ•  ๋•Œ ์‹œํฌ๋ฆฟ ์ฐฝ 2๊ฐœ์—์„œ ๋™์ผํ•œ IP, ID๋กœ ๋กœ๊ทธ์ธํ•  ๊ฒฝ์šฐ ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌํ•ด์•ผ ํ•˜๋Š”๊ฐ€์— ๋Œ€ํ•œ ๊ณ ๋ฏผ์—์„œ ์‹œ์ž‘๋˜์—ˆ๋‹ค. 

 

1. ๋™์‹œ ๋กœ๊ทธ์ธ ํ—ˆ์šฉ ์•ˆ ํ•จ 

๋‚˜์ค‘ ๋กœ๊ทธ์ธ์œผ๋กœ refresh_token_value์„ ๋ฎ์–ด์“ด๋‹ค

- ๋ฐœ์ƒ๋  ์ˆ˜ ์žˆ๋Š” ๋ฌธ์ œ์  : ์ฒซ๋ฒˆ์งธ ๋กœ๊ทธ์ธํ•œ ์‚ฌ์šฉ์ž๋Š” ํ† ํฐ์ด ๋งŒ๋ฃŒ๋˜์—ˆ๋Š”์ง€ / ํ•œ ๋ฒˆ๋” ๋กœ๊ทธ์ธ์„ ํ•ด์„œ 401์ด ๋œ๊ฑด์ง€ ์•Œ ์ˆ˜๊ฐ€ ์—†๋‹ค

- ๋ฐฑ์—”๋“œ : 401 ์‘๋‹ต ์‹œ ๋ณธ๋ฌธ์— { code: "TOKEN_EXPIRED" }, { code: "REPLACED_BY_NEW_LOGIN" } ๋“ฑ ํฌํ•จ

- ํ”„๋ก ํŠธ : ์„ธ๋ถ€ ์‘๋‹ต ๋ฉ”์‹œ์ง€ ํ™•์ธํ›„, localstorage ์ง€์šฐ๊ณ  ์„ธ๋ถ€ ์‘๋‹ต ์‚ฌ์šฉ์ž์—๊ฒŒ ์•ˆ๋‚ดํ•˜์—ฌ ๋‹ค์‹œ ๋กœ๊ทธ์ธ์ด ํ•„์š”ํ•จ์„ ๋ช…์‹œ

 

2. ์—ฌ๋Ÿฌ ๋””๋ฐ”์ด์Šค/๋ธŒ๋ผ์šฐ์ € ๋™์‹œ ๋กœ๊ทธ์ธ ํ—ˆ์šฉ 

ํ•œ ์œ ์ €๊ฐ€ ์—ฌ๋Ÿฌ ํ† ํฐ์„ ๋ณด์œ ํ•  ์ˆ˜ ์žˆ์œผ๋ฉด ๊ฐ ๋กœ๊ทธ์ธ ๋งˆ๋‹ค ๊ณ ์œ  session_id์„ ์ƒ์„ฑํ•œ๋‹ค 

์ด ๊ตฌ์กฐ๋ฉด ์—ฌ๋Ÿฌ ์‹œํฌ๋ฆฟ ์ฐฝ / ๋ธŒ๋ผ์šฐ์ € / ๊ธฐ๊ธฐ์—์„œ ๋™์‹œ์— ๋กœ๊ทธ์ธํ•  ์ˆ˜ ์žˆ๋‹ค 

๋‹จ ๋ณด์•ˆ์ƒ ๊ด€๋ฆฌ๊ฐ€ ํ•„์š”ํ•˜๊ธฐ ๋•Œ๋ฌธ์— ๋ฉ”ํƒ€๋ฐ์ดํ„ฐ๋ฅผ ์ถ”์ ํ•œ๋‹ค. 

 

 

๊ด€๋ฆฌ ํŽ˜์ด์ง€์—์„œ ์‚ฌ์šฉ์ž์—๊ฒŒ ๋ณธ์ธ ํ† ํฐ ๋ชฉ๋ก ๋ณด์—ฌ์คŒ (PC, ๋ชจ๋ฐ”์ผ, MFA ์—ฌ๋ถ€, ๋งˆ์ง€๋ง‰ ์ ‘์† ์‹œ๊ฐ„)

ํƒˆ์ทจ ์˜์‹ฌ์‹œ ๊ฐœ๋ณ„ ํ† ํฐ๋งŒ ํ๊ธฐ ๊ฐ€๋Šฅ (R2.revoked = true) 

token_table (
  token_id UUID PRIMARY KEY,
  user_id UUID,
  refresh_token TEXT,
  user_agent TEXT,
  ip_address TEXT,
  created_at TIMESTAMP,
  last_used_at TIMESTAMP,
  
  revoked BOOLEAN DEFAULT FALSE, # ํ๊ธฐ ์—ฌ๋ถ€ 
  client_type ENUM('WEB', 'MOBILE'), # ์›น/๋ชจ๋ฐ”์ผ ๋ฐฉ์‹ ๊ตฌ๋ถ„ 
  device_info TEXT, #์žฅ์น˜ ์ธ์ฆ(Device binding)
  mfa_verified BOOLEAN DEFAULT FALSE # MFA๋ฏธ์ธ์ฆ์‹œ ๊ถŒํ•œ์ œํ•œ 
)

 

 

 

์›น + ๋ชจ๋ฐ”์ผ ๋™์‹œ ์ง€์›์‹œ ๋ฐฉ์‹ ๊ตฌ๋ถ„์ด ํ•„์š”ํ•œ ์ด์œ  

์›น - RefreshToken์€ Secure, HttpOnly ๋กœ  ์„ค์ • 

์•ฑ - Access/Refresh Token์„ Authorization ํ—ค๋”๋กœ ๋ณด๋ƒ„, ๋กœ์ปฌ ์Šคํ† ๋ฆฌ์ง€์— refresh token์ €์žฅ 

 

 

ํ•œ ๋ฒˆ ์‚ฌ์šฉํ•œ Refresh Token์€ ๋ฌดํšจํ™”ํ•˜๊ณ  ์ƒˆ Refresh Token๋ฐœ๊ธ‰์„ ์ง„ํ–‰ํ•ด์•ผ ํ•œ๋‹ค. 

728x90

๊ด€๋ จ๊ธ€ ๋”๋ณด๊ธฐ