ํ‹ฐ์Šคํ† ๋ฆฌ ๋ทฐ

BackEnd

JWT

mokhs 2021. 6. 26. 19:01

JSON WEB TOKEN

JWT๋ž€?

  • ํ† ํฐ ์ž์ฒด์— ์ •๋ณด๋ฅผ ๋‹ด๊ณ  ์žˆ์Œ
  • ๋ฌด๊ฒ์ง€ ์•Š๊ณ 
  • ๊ฐ„ํŽธํ•˜๊ณ 
  • ์‰ฝ๊ฒŒ ์ ์šฉ ๊ฐ€๋Šฅ
  • Base64 URL Safe Encoding์„ ์ด์šฉํ•ด์„œ URL, Cooke, Header ๋“ฑ์— ์‚ฌ์šฉ ๊ฐ€๋Šฅ
  • ์ค‘์•™์˜ ์ธ์ฆ ์„œ๋ฒ„, ๋ฐ์ดํ„ฐ ์Šคํ† ์–ด์— ๋Œ€ํ•œ ์˜์กด์„ฑ์ด ์—†์–ด์„œ ์‹œ์Šคํ…œ ์ˆ˜ํ‰ ํ™•์žฅ์— ์œ ๋ฆฌํ•จ
  • → ๊ธฐ์กด์— ์ธ์ฆ ์ •๋ณด๋ฅผ ์„ธ์…˜์— ์ €์žฅํ•˜๋Š” ๋ฐฉ์‹์€ ํ•ด๋‹น ์„œ๋ฒ„์—์„œ๋งŒ ํ•ด๋‹น ์ธ์ฆ ์ •๋ณด๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์–ด์„œ ๋”ฐ๋กœ ์„ธ์…˜ ์„œ๋ฒ„๋ฅผ ๋‘ฌ์•ผํ–ˆ์ง€๋งŒ, ํ† ํฐ์€ ํด๋ผ์ด์–ธํŠธ์— ์ €์žฅ๋˜๊ธฐ ๋•Œ๋ฌธ์— ์„ธ์…˜ ์„œ๋ฒ„๊ฐ€ ํ•„์š” ์—†์–ด์ง.

JWT๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์€ 3๊ฐœ์˜ ๋ถ€๋ถ„์œผ๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ์Œ

aaaaaa.bbbbbb.cccccc
// ์•ž์—์„œ๋ถ€ํ„ฐ .์„ ๊ธฐ์ค€์œผ๋กœ ๋‹ค์Œ๊ณผ ๊ฐ™์Œ

// ํ—ค๋”(header).๋‚ด์šฉ(payload).์„œ๋ช…(signature)

ํ—ค๋”(Header)

  • Signature๋ฅผ ํ•ด์‹ฑํ•˜๊ธฐ ์œ„ํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ •๋ณด
const header = {
  "typ": "JWT",
  "alg": "HS256"
}

Header๋Š” ๋‘๊ฐ€์ง€ ์ •๋ณด๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์Œ

typ : ํ† ํฐ์˜ ํƒ€์ž…์„ ์ง€์ • → JWT

alg : ํ•ด์‹ฑ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์ง€์ •

alg์— ๊ธฐ์ˆ ํ•œ ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ํ† ํฐ์„ ๊ฒ€์ฆํ•  ๋•Œ signature๋ถ€๋ถ„์—์„œ ์‚ฌ์šฉ๋จ!

→ ์•”ํ˜ธํ™”ํ•ด์„œ ์“ธ ๊ฒƒ ๊ฐ™์€ ๋Š๋‚Œ์ด ํŒํŒ!

์ •๋ณด(Payload)

  • ์„œ๋ฒ„์™€ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ์ฃผ๊ณ ๋ฐ›๋Š”, ์‹œ์Šคํ…œ์—์„œ ์‹ค์ œ๋กœ ์‚ฌ์šฉ๋  ์ •๋ณด์— ๋Œ€ํ•œ ๋‚ด์šฉ๋“ค์„ ๋‹ด๊ณ  ์žˆ์Œ.
{
    "sub" : "mokhs00",
    "auth" : "ROLE_USER"
    "exp" : 1480849147370
}

ํด๋ ˆ์ž„(claim)

Payload ๋ถ€๋ถ„์— ๋‹ด๋Š” ์ •๋ณด์˜ ํ•œ ์กฐ๊ฐ์„ ํด๋ ˆ์ž„(claim)์ด๋ผ๊ณ  ๋ถ€๋ฆ„

key / value ํ•œ ์Œ์œผ๋กœ ์ด๋ฃจ์–ด์ง

ํด๋ ˆ์ž„๋„ ํฌ๊ฒŒ ์„ธ ๋ถ„๋ฅ˜๋กœ ๋‚˜๋‰˜์–ด์ง

  • ๋“ฑ๋ก๋œ(registered) ํด๋ ˆ์ž„
  • ๊ณต๊ฐœ(public) ํด๋ ˆ์ž„
  • ๋น„๊ณต๊ฐœ(private) ํด๋ ˆ์ž„

1. ๋“ฑ๋ก๋œ(registered) ํด๋ ˆ์ž„

  • ๋“ฑ๋ก๋œ ํด๋ ˆ์ž„๋“ค์€ ์„œ๋น„์Šค์—์„œ ํ•„์š”ํ•œ ์ •๋ณด๋“ค์ด ์•„๋‹Œ, ํ† ํฐ์— ๋Œ€ํ•œ ์ •๋ณด๋“ค์„ ๋‹ด๊ธฐ ์œ„ํ•ด์„œ ์ด๋ฆ„์ด ์ด๋ฏธ ์ •ํ•ด์ ธ์žˆ๋Š” ํด๋ ˆ์ž„!

→ ๊ทธ๋ƒฅ ์ŠคํŽ™์œผ๋กœ ๋Š๊ปด์ง. ์ด๋ฏธ ๋“ฑ๋ก๋˜์–ด ์žˆ๋‹ค๋Š” ์˜๋ฏธ์—์„œ ๋ช…์นญ์ด registered์ธ๋“ฏ

  • ๋“ฑ๋ก๋œ ํด๋ ˆ์ž„์˜ ์‚ฌ์šฉ์€ ๋ชจ๋‘ ์„ ํƒ์ ์ž„

→ ์“ฐ๋“  ์•ˆ ์“ฐ๋“  ์ž์œ ๋ผ๋Š” ๋ง

๋“ฑ๋ก๋œ ํด๋ ˆ์ž„ ์ข…๋ฅ˜

๋ฐ‘์ค„ ์นœ ๊ฒƒ๋“ค์€ ์ค‘์š”ํ•˜๋‹ค๊ณ  ์ƒ๊ฐํ•จ.

  • iss : ํ† ํฐ ๋ฐœ๊ธ‰์ž (issuer)
  • sub : ํ† ํฐ ์ œ๋ชฉ (subject)
  • aud : ํ† ํฐ ๋Œ€์ƒ์ž (audience)
  • exp : ํ† ํฐ ๋งŒ๋ฃŒ ์‹œ๊ฐ„ (expiration) ์‹œ๊ฐ„์€ NumericDate ํ˜•์‹์„ ๋˜์–ด์žˆ์–ด์•ผ ํ•จ.
    ๋‹น์—ฐํ•œ ์ด์•ผ๊ธฐ์ง€๋งŒ, ์–ธ์ œ๋‚˜ ํ˜„์žฌ ์‹œ๊ฐ„๋ณด๋‹ค ์ดํ›„๋กœ ์„ค์ •ํ•ด์•ผํ•จ.
  • nbf : Not Before์„ ์˜๋ฏธ, ํ† ํฐ์˜ ํ™œ์„ฑ ๋‚ ์งœ์™€ ๋น„์Šทํ•œ ๊ฐœ๋…. exp์™€ ๋™์ผํ•˜๊ฒŒ NumericDate ํ˜•์‹์œผ๋กœ ๋‚ ์งœ๋ฅผ ์ง€์ •. ํ•ด๋‹น ๋‚ ์งœ๊ฐ€ ์ง€๋‚˜๊ธฐ ์ „๊นŒ์ง€ ํ† ํฐ์ด ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š์Œ
  • iat : ํ† ํฐ์ด ๋ฐœ๊ธ‰๋œ ์‹œ๊ฐ„ (issued at). ์ด ๊ฐ’์„ ์‚ฌ์šฉํ•˜์—ฌ ํ† ํฐ์˜ age ๊ฐ€ ์–ผ๋งˆ๋‚˜ ๋˜์—ˆ๋Š”์ง€ ํŒ๋‹จํ•  ์ˆ˜ ์žˆ์Œ.
  • jti :JWT์˜ ๊ณ ์œ  ์‹๋ณ„์ž, ์ฃผ๋กœ ์ค‘๋ณต์ ์ธ ์ฒ˜๋ฆฌ๋ฅผ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด์„œ ์‚ฌ์šฉ๋จ. ์ผํšŒ์šฉ ํ† ํฐ์— ์‚ฌ์šฉํ•˜๋ฉด ์œ ์šฉํ•จ!

2. ๊ณต๊ฐœ(public) ํด๋ ˆ์ž„

๊ณต๊ฐœ ํด๋ ˆ์ž„๋“ค์€ ์ถฉ๋Œ์ด ๋ฐฉ์ง€๋œ (collision-resistant) ์ด๋ฆ„์„ ๊ฐ€์ง€๊ณ  ์žˆ์–ด์•ผํ•จ.

์ถฉ๋Œ์„ ๋ฐฉ์ง€ํ•˜๊ธฐ ์œ„ํ•ด์„œ, ํด๋ ˆ์ž„ ์ด๋ฆ„์„ URI ํ˜•์‹์œผ๋กœ ์ง€์Œ

{
    "https://www.naver.com/jwt_claims/is_admin" : true
}

3. ๋น„๊ณต๊ฐœ(private) ํด๋ ˆ์ž„

ํ† ํฐ์„ ์‚ฌ์šฉํ•˜๋Š” ์–‘ ์ธก๊ฐ„(ํด๋ผ์ด์–ธํŠธ <-> ์„œ๋ฒ„) ํ˜‘์˜ ํ•˜์— ์‚ฌ์šฉ๋˜๋Š” ํด๋ ˆ์ž„ ์ด๋ฆ„๋“ค

์ด๋ฆ„์ด ์ค‘๋ณต๋˜์–ด ์ถฉ๋Œ์ด ์ƒ๊ธธ ์ˆ˜ ์žˆ์œผ๋‹ˆ ์ฃผ์˜

{
  "username" : "mokhs00"
}

ex) PayLoad

{
    "iss" : "mokhs.com",
  "exp" : "1623857327070",
    "userId" : "5190",
    "username" : "mokhs"
}

โ—์ฃผ์˜ - Base64 encoding์˜ padding ๋ฌธ์ž์™€ url-safe

base64 ์ธ์ฝ”๋”ฉ ์‹œ์— = ๋ฌธ์ž๊ฐ€ ํ•œ ๋‘๊ฐœ ๋ถ™์„ ์ˆ˜ ์žˆ์Œ.
์ด๋Š” base64 ์ธ์ฝ”๋”ฉ์˜ padding ๋ฌธ์ž๋ผ๊ณ  ๋ถˆ๋ฆผ

๊ทธ๋Ÿฐ๋ฐ =์€ ํŒŒ๋ผ๋ฏธํ„ฐ๋กœ ์ธ์‹๋  ์ˆ˜ ์žˆ๊ธฐ์— url-safeํ•˜์ง€ ์•Š์Œ

๋”ฐ๋ผ์„œ ํŒจ๋”ฉ ๋ฌธ์ž๋ฅผ ๋ชจ๋‘ ์ง€์›Œ์ค˜์•ผํ•จ!

  • ํŒจ๋ฐ ๋ฌธ์ž๋ฅผ ์ œ๊ฑฐํ•ด๋„ decoding ์‹œ ์ „ํ˜€ ๋ฌธ์ œ๊ฐ€ ๋˜์ง€ ์•Š์Œ

์„œ๋ช…(Signature)

  • JWT์˜ ๋งˆ์ง€๋ง‰ ๋ถ€๋ถ„!
  • ํ† ํฐ์˜ ์œ ํšจ์„ฑ ๊ฒ€์ฆ์„ ์œ„ํ•œ ๋ฌธ์ž์—ด
    • ์ด ๋ฌธ์ž์—ด์„ ํ†ตํ•ด ์„œ๋ฒ„์—์„œ ์ด ํ† ํฐ์ด ์œ ํšจํ•œ ํ† ํฐ์ธ์ง€ ๊ฒ€์ฆ ๊ฐ€๋Šฅ
  • ํ—ค๋”(header)์˜ ์ธ์ฝ”๋”ฉ๊ฐ’, ์ •๋ณด(payload)์˜ ์ธ์ฝ”๋”ฉ๊ฐ’์„ ํ•ฉ์นœ ํ›„ ์ฃผ์–ด์ง„ ๋น„๋ฐ€ํ‚ค๋กœ ํ•ด์‹ฑ(hash)ํ•˜์—ฌ ์ƒ์„ฑ
  • ์„œ๋ช… ๋ถ€๋ถ„์„ ๋งŒ๋“œ๋Š” ์Šˆ๋„์ฝ”๋“œ(pseudocode)๊ตฌ์กฐ๋Š” ๋‹ค์Œ๊ณผ ๊ฐ™์Œ
HMACSHA256(
    base64UrlEncode(header) + "." +
  base64UrlEncode(payload),
  secret
)
  • ๊ทธ๋ฆฌ๊ณ  ์ด๋ ‡๊ฒŒ ๋งŒ๋“  hash๋ฅผ base64์ธ์ฝ”๋”ฉ์„ ํ•˜๋ฉด ๋งˆ์ง€๋ง‰ signature๋ถ€๋ถ„์ด ์™„์„ฑ๋จ!
  • ์—ฌ๊ธฐ์„œ ํ•ต์‹ฌ์€ secret์ž„ ์„œ๋ฒ„์— ๊ณ ์œ ํ•œ secret ๊ฐ’์„ ๋‘๋ฉด ํ•ด๋‹น ์„œ๋ฒ„๋งŒ ์ธ์ฆ์ด ๊ฐ€๋Šฅํ•จ
    • secret์ด ์žˆ๊ธฐ์— ํ† ํฐ์˜ ์œ„๋ณ€์กฐ๋ฅผ ๋ง‰์„ ์ˆ˜ ์žˆ์Œ
    • ๋งŒ์•ฝ ํ† ํฐ ๋‚ด์šฉ์ด ์œ„๋ณ€์กฐ๋˜์–ด๋„ secret์„ ๋„ฃ๊ณ  hashํ–ˆ์„ ๋•Œ ๊ธฐ์กด ์„œ๋ช…(signature)์™€ ์ผ์น˜ํ•˜์ง€ ์•Š์œผ๋ฉด, ์„œ๋ฒ„์—์„  ์ธ์ฆ ๊ฑฐ๋ถ€๋ฅผ ํ•˜๋ฉด ๋จ!

header.payload.signature ํ•ฉ์น˜๊ธฐ

  • ๊ฐ ๋ถ€๋ถ„์˜ ์ค‘๊ฐ„ ๋ถ€๋ถ„์— ๋ฌธ์ž์—ด "."์„ ๋ถ™์—ฌ์„œ ํ•ฉ์น˜๋ฉด ํ† ํฐ ์™„์„ฑ!

๋งˆ๋ฌด๋ฆฌ

JWT ์žฅ์ 

  • ์ค‘์•™์˜ ์ธ์ฆ ์„œ๋ฒ„, ๋ฐ์ดํ„ฐ ์Šคํ† ์–ด์— ๋Œ€ํ•œ ์˜์กด์„ฑ์ด ์—†์Œ.

→ ์‹œ์Šคํ…œ ์ˆ˜ํ‰ ํ™•์žฅ์— ์œ ๋ฆฌ

  • Base64 URL Safe Encoding ์‚ฌ์šฉ

→ URL, Cooke, Header ๋ชจ๋‘ ์‚ฌ์šฉ ๊ฐ€๋Šฅ

  • { token : "header.payload.signature" }

JWT ๋‹จ์ 

  • Payload์˜ ์ •๋ณด๊ฐ€ ๋งŽ์•„์ง€๋ฉด ๋„คํŠธ์›Œํฌ ์‚ฌ์šฉ๋Ÿ‰ ์ฆ๊ฐ€, ๋ฐ์ดํ„ฐ ์„ค๊ณ„ ๊ณ ๋ ค ํ•„์š”
  • ํ† ํฐ์ด ํด๋ผ์ด์–ธํŠธ์— ์ €์žฅ๋จ, ์„œ๋ฒ„์—์„œ ํด๋ผ์ด์–ธํŠธ์˜ ํ† ํฐ์„ ์กฐ์ž‘ํ•  ์ˆ˜ ์—†์Œ.

์ฐธ๊ณ 

https://velopert.com/2389

๋ฐ˜์‘ํ˜•