- Header(ํค๋)
- Payload(ํ์ด๋ก๋)
- Signature(์๋ช )
Header
- ํ ํฐ์ ์ ํ(๋ณดํต "JWT")
- ์๋ช ์ ์ฌ์ฉ๋ ์๊ณ ๋ฆฌ์ฆ์ ์ ์(์: HMAC SHA256, RSA ๋ฑ)
{ "alg": "HS256", "typ": "JWT" }
Payload
{ "sub": "user123", "name": "John Doe", "iat": 1712016000, "exp": 1712023200 }
Signature
HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
์๋ฒ์ ๋น๋ฐ ํค - ์๋ฒ์ ๋น๋ฐ ํค(secret key)๋ ์๋ฒ ์ ํ๋ฆฌ์ผ์ด์ ์ด ์ค๊ณ๋๊ณ ๋ฐฐํฌ๋๋ ๋จ๊ณ์์ ์์ฑ๋๊ฑฐ๋ ์ค์ ๋ฉ๋๋ค. - JWT๋ฅผ ์์ฑํ๊ณ ๊ฒ์ฆํ๊ธฐ ์ํด ์๋ฒ ์ธก์์ ๋ฏธ๋ฆฌ ์ค์ ๋๊ณ ๊ด๋ฆฌ๋๋ ๊ณ ์ ๋ ๊ฐ์ ๋๋ค. - ์ด ํค๋ JWT์ Signature ๋ถ๋ถ์ ์์ฑํ๊ณ , ๋์ค์ ํ ํฐ์ ์ ํจ์ฑ์ ๊ฒ์ฆํ ๋ ์ฌ์ฉ๋ฉ๋๋ค.
์ฅ์
- ์ํ ๋น์ ์ฅ(Stateless): ์ฌ์ฉ์ ์ธ์ฆ์ ๋ณด๋ฅผ ์๋ฒ๋ ์ธ์ ์คํ ๋ฆฌ์ง์ ์ ์งํ ํ์๊ฐ ์์ด ํ์ฅ์ฑ์ด ๋ฐ์ด๋๊ณ , ๋ถ์ฐ ์์คํ ์์ ์ ๋ฆฌํฉ๋๋ค.
- ๋จ์ผ ํ ํฐ์ผ๋ก ์ธ์ฆ : ์ฌ์ฉ์ ์ธ์ฆ์ ํ์ํ ์ ๋ณด๋ฅผ ํ ํฐ ์์ฒด์ ๋ด๊ณ ์์ด ํด๋ผ์ด์ธํธ ์ธก์์ ๋ค์ด์ค๋ ์์ฒญ๋ง์ผ๋ก ์ ํจ์ฑ ๊ฒ์ฌ๋ฅผ ํฉ๋๋ค. API ํธ์ถ ์๋ง๋ค ํค๋(Authorization: Bearer
)์ ํฌํจ์์ผ ๊ฐ๋จํ ์ธ์ฆ์ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค. - ํธํ์ฑ : JSON ๊ธฐ๋ฐ์ด๋ฏ๋ก ๋ค์ํ ํ๋ซํผ๊ณผ ์ธ์ด์์ ์ฝ๊ฒ ํ์ฑํ๊ณ ์ฌ์ฉํ ์ ์์ต๋๋ค.
๋จ์ ๋ฐ ๊ณ ๋ ค์ฌํญ
- ์์ ๋ฐ ํ๊ธฐ ๋ถ๊ฐ : ํ ๋ฒ ๋ฐ๊ธ๋ JWT๋ ๋ง๋ฃ ์ ๊น์ง ์ ํจํ๋ฉฐ ์ค๊ฐ์ ๋ฌดํจํํ๊ธฐ ์ด๋ ต์ต๋๋ค. ์ด๋ฅผ ๋ณด์ํ๋ ค๋ฉด Refresh Token์ ํจ๊ป ์ฌ์ฉํด ์งง์ ์ ํจ๊ธฐ๊ฐ์ Access Token์ ์ฃผ๊ธฐ์ ์ผ๋ก ๊ฐฑ์ ํ๋ ๋ฐฉ์์ด ์ผ๋ฐ์ ์ ๋๋ค.
- ํ ํฐ ํ์ทจ ์ํ : ํ ํฐ์ด ํด๋ผ์ด์ธํธ์ ์ ์ฅ๋๋ฏ๋ก(์ฃผ๋ก ๋ธ๋ผ์ฐ์ ์ localStorage๋ cookie), XSS(Cross-Site Scripting) ๊ณต๊ฒฉ์ ๋ ธ์ถ๋ ๊ฐ๋ฅ์ฑ์ด ์์ต๋๋ค. ์ด๋ฅผ ๋ฐฉ์งํ๋ ค๋ฉด HTTPS๋ฅผ ์ฌ์ฉํ๊ณ , ํ ํฐ์ HttpOnly, Secure ์์ฑ์ด ์ค์ ๋ ์ฟ ํค์ ์ ์ฅํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
- Payload ๋ ธ์ถ : JWT์ Payload๋ ์ํธํ๋์ง ์๊ณ Base64๋ก ์ธ์ฝ๋ฉ๋ง ๋์ด ์์ด ๋๊ตฌ๋ ๋์ฝ๋ฉํด ๋ด์ฉ์ ๋ณผ ์ ์์ต๋๋ค. ๋ฐ๋ผ์ ๋ฏผ๊ฐํ ์ ๋ณด(์: ๋น๋ฐ๋ฒํธ)๋ ์ ๋ ํฌํจ์ํค์ง ์์์ผ ํฉ๋๋ค.
ํ ํฐ ํ์ทจ ์ํ
HttpOnly HttpOnly๋ ์ฟ ํค์ ๋ถ์ด๋ ์์ฑ ์ค ํ๋๋ก, JavaScript์์ ํด๋น ์ฟ ํค์ ์ ๊ทผํ์ง ๋ชปํ๊ฒ ๋ง๋ ๊ธฐ๋ฅ์ ๋๋ค. SecureHTTPS์์๋ง ์ ์ก๋๊ฒ ํ๋ ์์ฑ ์ ๋๋ค. SameSiteCSRF ๋ฐฉ์ง๋ฅผ ์ํด ์ฟ ํค๊ฐ ์ด๋ค ์ํฉ์์ ์๋์ผ๋ก ๋ธ๋ผ์ฐ์ ์ ์ ์ก๋ ์ง๋ฅผ ์ ํํ๋ ์์ฑ์ ๋๋ค.SameSite=Strict ์ค์ ์ผ๋์๋ ์ฟ ํค๊ฐ ๋์ผ ์ถ์ฒ ์์ฒญ์๋ง ์ ์ก๋๋๋ก ์ค์ ํฉ๋๋ค.
Set-Cookie : sessionId=abc123; Secure; HttpOnly; SameSite=Strict //JavaScript๋ก ์ ๊ทผ ๋ถ๊ฐ console.log(document.cookie); // "" (๋น ๋ฌธ์์ด ์ถ๋ ฅ)
Set-Cookie: token=eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ1c2VyMTIzIn0.์๋ช ; Path=/; Secure; HttpOnly
์ ํจ๊ธฐ๊ฐ ์ค์ ์ ์ค์์ฑ
- ์ ํจ๊ธฐ๊ฐ(exp)์ ์งง๊ฒ ์ค์ ํ๋ ๊ฒ์ ๋ณด์์ ๊ฐํํ๋ ํต์ฌ ๋ฐฉ๋ฒ์ ๋๋ค. ์๋ฅผ ๋ค์ด, Access Token์ 15๋ถ~1์๊ฐ, Refresh Token์ ํ๋ฃจ ์ ๋๋ก ์ค์ ํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค. ์ ํจ๊ธฐ๊ฐ์ด ๊ธธ๋ฉด ํ ํฐ์ด ์ ์ถ๋์์ ๋ ์ ์ฉ๋ ์๊ฐ์ด ๋์ด๋๋ฏ๋ก, ์งง์ ์ฃผ๊ธฐ๋ก ๊ฐฑ์ ํ๋ฉฐ ๋ณด์๊ณผ ํธ์์ฑ์ ๊ท ํ ์๊ฒ ์ ์งํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
๋ก๊ทธ์ธ ๊ณผ์ ์์์ JWT
- ์ฌ์ฉ์์ ์๊ฒฉ ์ฆ๋ช (์: ID, ๋น๋ฐ๋ฒํธ)์ ํ์ธํฉ๋๋ค.
- ์ธ์ฆ์ด ์ฑ๊ณตํ๋ฉด, ์๋ฒ๋ ๋ฏธ๋ฆฌ ์ค์ ๋ ๋น๋ฐ ํค๋ฅผ ์ฌ์ฉํด JWT๋ฅผ ์์ฑํฉ๋๋ค.
- ์์ฑ๋ JWT(ํค๋.ํ์ด๋ก๋.์๋ช ํํ)๋ ์ฌ์ฉ์์๊ฒ ๋ฐํ๋ฉ๋๋ค.
- ๋น๋ฐ ํค: my-secret-key (์๋ฒ์ ๊ณ ์ ์ ์ผ๋ก ์ ์ฅ๋จ)
- JWT: eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ1c2VyMTIzIn0.์๋ช ๊ฐ