์์ฆ ๋ฉด์ ์์ โJWT ํ์ทจ ์ ๋์ฒ ๋ฐฉ์?โ ๊ฐ์ ์ง๋ฌธ์ ์ ๋ง ๋ง์ด ๋ฐ๋๋ค. ๋ณด์ ์ด์๊ฐ ์ค์ํด์ง๋ค ๋ณด๋, ์ธ์ฆ/์ธ๊ฐ ๊ด๋ จ ์ง๋ฌธ ๋น์ค๋ ์ ์ ์ปค์ง๋ ๋๋์ด๋ค. ๋๋ ์ฒ์์๋ ์ด ์ง๋ฌธ์ด ๋๋ฌด ๋ง๋งํด์ ํ๋ค์๋ ๊ฒฝํ์ด ์๋ค. ์ ๋ต์ด ๋ฑ ์ ํด์ ธ ์๋ ์ฃผ์ ๋ ์๋๊ณ , ์ํฉ๋ง๋ค ๋์์ด ๋ฌ๋ผ์ง๊ธฐ ๋๋ฌธ์ด๋ค.
๊ทธ๋์ ์ด๋ฒ ๊ธฐํ์ ๋ด๊ฐ ์๊ฐํ๊ณ ์ ๋ฆฌํ ๋ด์ฉ์ ํ๋ฒ ๊ธฐ๋กํด๋ณด๋ ค๊ณ ํ๋ค.

์ฐ๋ฆฌ๋ ํ๋ก์ ํธ๋ฅผ ํ ๋ JWT(JSON Web Token)์ ์ ๋ง ๋ง์ด ์ฌ์ฉํ๋ค. ์ฟ ํค ๊ธฐ๋ฐ ์ธ์ฆ์ ์๋๋ ๋น ๋ฅด์ง๋ง ๋ณด์์ ์ทจ์ฝํ๊ณ , ์ธ์ ๊ธฐ๋ฐ ์ธ์ฆ์ ์๋ฒ์ ์ธ์ ์ ์ ์ฅํด์ผ ํด์ ์์์ ๋ง์ด ์ฌ์ฉํ๋ค. ๊ทธ๋ฐ ์ด์ ๋ค ๋๋ฌธ์ ์์ฆ์ JWT๋ฅผ ์ ํธํ๋ ๋ถ์๊ธฐ๋ค. ์์งํ ๋งํ๋ฉด, ๋ง์ ๊ฐ๋ฐ์๋ค์ด โ์์ฆ ํธ๋ ๋๊ฐ JWT๋๊น!โ ํ๋ฉด์ ์ผ๋จ ์ฐ๊ณ ๋ณธ๋ค. ๋ ์ญ์๋ ์ฒ์์๋ ์ ๋๋ก ์ดํดํ์ง ์์ ์ฑ, ๊ทธ๋ฅ ๋ค๋ค ์ฐ๋๊น ๋ฐ๋ผ์ ์ฌ์ฉํ๋ ๊ฒ ์ฌ์ค์ด๋ค. ๊ทธ๋ฐ๋ฐ ๋ฌธ๋ ์ด๋ฐ ์๊ฐ์ด ๋ค์๋ค. ๋๋์ฒด JWT๊ฐ ๋ญ๊ธธ๋ ์ด๋ ๊ฒ ๋ชจ๋๊ฐ ์ฌ์ฉํ๋ ๊ฑธ๊น? ๊ทธ๊ฒ ๋ณด์์ ์ผ๋ก ์๋ฒฝํ ์กด์ฌ์ธ๊ฐ? ์๋๋ฉด ๋จ์ํ ์๋ฒ ์์์ ์๋ผ๊ธฐ ์ํ ์๋จ์ผ ๋ฟ์ธ๊ฐ? ๊ทธ๋์ ์ด๋ฒ์๋ ๊ทธ๋์ ๊ฐ๋ณ๊ฒ๋ง ์๊ณ ๋์ด๊ฐ๋ JWT์ ๋ํด ์ง์ ์ ๋ฆฌํด๋ณด๊ณ ์ ๋๋ก ์ดํดํด๋ณด๋ ค๊ณ ํ๋ค.
์ผ๋จ HTTP์ ํน์ฑ๋ถํฐ ์ง๊ณ ๋์ด๊ฐ์. ์ฐ๋ฆฌ๊ฐ ํํ ์๊ณ ์๋ฏ์ด HTTP๋ Statelessํ๊ณ Connectionlessํ ํน์ง์ ๊ฐ์ง๊ณ ์๋ค.
ํ๋ง๋๋ก ๋งํ๋ฉด, ์๋ฒ๋ ์์ฒญ(Request)์ด ๋ค์ด์ฌ ๋๋ง๋ค ๊ทธ๋๊ทธ๋ ์๋ต(Response)์ ๋ณด๋ด์ค ๋ฟ, ํด๋ผ์ด์ธํธ๊ฐ ๋๊ตฌ์๊ณ ์ด๋ค ์ํ์๋์ง๋ฅผ ๊ธฐ์ตํ์ง ์๋๋ค๋ ๊ฒ์ด๋ค. ๋ํ ์์ฒญ์ด ๋๋๋ฉด ์ฐ๊ฒฐ์ ์ ์งํ์ง ์๊ธฐ ๋๋ฌธ์ ์ง์์ ์ผ๋ก ์ฐ๊ฒฐ๋์ด ์๋ ์ํ๋ ์๋๋ค.
๋ฐ๋ผ์ ์ด๊ฑธ ํด๊ฒฐํด์ฃผ๋ ๊ฒ์ด ๋ฌด์์ด๋? ๋ฐ๋ก ์ฟ ํค(Cookie)์ ์ธ์ (Session)์ด๋ค.
์ฟ ํค(Cookie)๋, ์น์ฌ์ดํธ๊ฐ ์ฌ์ฉ์์ ๋ธ๋ผ์ฐ์ ์ ์ ์ฅํ๋ ์์ ๋ฐ์ดํฐ ํ์ผ์ ๋งํ๋ค.
Set-Cookie: userName=kevin; password=abc123
๋ก๊ทธ์ธ ์์ฒญ์ ๋ํด ์๋ฒ๋ ์๋ต ํค๋์ Set-Cookie๋ฅผ ๋ด์ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ํด๋ผ์ด์ธํธ์ ์ ๋ฌํ๋ค.
๊ทธ ์ดํ ์ฌ์ฉ์๋ ๋ชจ๋ ์์ฒญ๋ง๋ค ์ฟ ํค๋ฅผ ํจ๊ป ์ ์กํ๊ณ , ์๋ฒ๋ ํด๋น ์ฟ ํค ๊ฐ์ผ๋ก ์ฌ์ฉ์๋ฅผ ์๋ณํ ์ ์๋ค.
ํ์ง๋ง ์ฟ ํค ๋ฐฉ์์๋ ๋ถ๋ช ํ ๋จ์ ์ด ์๋ค.
๋ณด์์ ์ทจ์ฝ
์ฟ ํค ๊ฐ์ด ํ์ทจ๋๊ฑฐ๋ ์กฐ์๋ ์ํ์ด ์๋ค. (ํนํ ๋น๋ฐ๋ฒํธ ๊ฐ์ ๋ฏผ๊ฐ ์ ๋ณด๋ ์ ๋ ๋ด์์๋ ์ ๋๋ค)
์ ์ฅ ์ฉ๋ ์ ํ ์กด์ฌ
๋ธ๋ผ์ฐ์ ๊ฐ ๊ณต์ ๋ถ๊ฐ
์ฟ ํค ํฌ๊ธฐ๊ฐ ์ปค์ง๋ฉด ๋คํธ์ํฌ ๋ถํ ์ฆ๊ฐ
์ฆ, ํด๋ผ์ด์ธํธ์ ์ค์ํ ์ ๋ณด๋ฅผ ์ ์ฅํ๋ค๋ ๊ฒ ์์ฒด๊ฐ ์ํํ๋ค๋ ๊ทผ๋ณธ์ ํ๊ณ๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
์ฟ ํค๋ง์ผ๋ก ํด๋ผ์ด์ธํธ์ ๋ก๊ทธ์ธ ์ํ๋ฅผ ์ ์งํ ์ ์์์ง๋ง, ๊ฐ์ฅ ํฐ ๋จ์ ์ ์ฟ ํค๊ฐ ํ์ทจ๋๊ฑฐ๋ ์กฐ์๋ ์ํ์ด ์๋ค๋ ์ ์ด๋ค. ํนํ, ๋ฏผ๊ฐํ ๊ฐ์ธ์ ๋ณด๋ฅผ HTTP๋ก ์ฃผ๊ณ ๋ฐ๋ ๊ฒ์ ๋งค์ฐ ์ํํ๋ค.
์ด๋ฅผ ๋ณด์ํ๊ธฐ ์ํด ์ธ์ (Session) ๋ฐฉ์์ด ๋ฑ์ฅํ๋ค. ์ธ์ ์ ๋น๋ฐ๋ฒํธ ๋ฑ ์ค์ํ ์ธ์ฆ ์ ๋ณด๋ฅผ ์๋ฒ ์ธก์ ์ ์ฅํ๊ณ , ํด๋ผ์ด์ธํธ์๋ ์ธ์ ID๋ง ์ฟ ํค๋ก ์ ๋ฌํ๋ค.
HTTP/1.1 200
Set-Cookie: JSESSIONID=FDB5E30BF20045E8A9AAFC788383680C;
์๋ฒ๋ ๋ก๊ทธ์ธ ์์ฒญ ์ ์ธ์ฆ ์ ๋ณด๋ฅผ ์๋ฒ์ ์ ์ฅํ๊ณ , ํด๋ผ์ด์ธํธ์๋ ์๋ณ์ฉ ์ธ์ ID(JSESSIONID)๋ฅผ ์ฟ ํค์ ๋ด์ ์ ๋ฌํ๋ค.
์ดํ ํด๋ผ์ด์ธํธ๋ ์์ฒญํ ๋๋ง๋ค JSESSIONID ์ฟ ํค๋ฅผ ํจ๊ป ์ ์กํ๊ณ , ์๋ฒ๋ ์ด๋ฅผ ํ์ธํด ํด๋ผ์ด์ธํธ๋ฅผ ์๋ณํ๋ค.
์ฅ์
์ธ์ ID๋ง ์ ๋ฌ๋๋ฏ๋ก, ์ฟ ํค๊ฐ ๋ ธ์ถ๋์ด๋ ์ค์ํ ๊ฐ์ธ์ ๋ณด๋ ์์ ํ๋ค.
๊ฐ ์ฌ์ฉ์๋ง๋ค ๊ณ ์ ์ธ์ ID๊ฐ ๋ฐ๊ธ๋๋ฏ๋ก, ์์ฒญ ์ ํ์์ ๋ณด๋ฅผ ์ฝ๊ฒ ํ์ธ ๊ฐ๋ฅํ๋ค.
๋จ์
์ธ์ ID๊ฐ ํ์ทจ๋๋ฉด, ๊ณต๊ฒฉ์๊ฐ ํด๋ผ์ด์ธํธ์ธ ์ฒ ์์ฅํ ์ ์๋ค.
์๋ฒ์ ์ธ์ ์ ๋ณด๋ฅผ ์ ์ฅํด์ผ ํ๋ฏ๋ก, ์ฌ์ฉ์ ์์ฒญ์ด ๋ง์์ง๋ฉด ์๋ฒ ๋ถํ์ ํ์ฅ์ฑ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ค.
์์ ์ดํด๋ณธ ์ฟ ํค/์ธ์ ๊ธฐ๋ฐ ์ธ์ฆ์ ๊ฐ๊ฐ ์ฅ์ ์ด ์์ง๋ง, ๋์์ ํ๊ณ๋ ์กด์ฌํ๋ค.
์ฟ ํค: ํด๋ผ์ด์ธํธ์ ๋ฏผ๊ฐ ์ ๋ณด๋ฅผ ๋ด์ ๊ฒฝ์ฐ ๋ณด์์ ์ทจ์ฝ
์ธ์ : ์๋ฒ์ ์ธ์ฆ ์ ๋ณด๋ฅผ ์ ์ฅํด์ผ ํ๋ฏ๋ก ์๋ฒ ๋ถํ ๋ฐ ํ์ฅ์ฑ ๋ฌธ์ ๋ฐ์
์ด๋ฌํ ๋ฌธ์ ๋ฅผ ๊ฐ์ ํ๊ณ ์ ๋ฑ์ฅํ ๊ฒ์ด JWT(Json Web Token, JWT) ๊ธฐ๋ฐ ์ธ์ฆ์ด๋ค.
JWT(JSON Web Token)๋ ์ธ์ฆ์ ํ์ํ ์ ๋ณด๋ฅผ ์ํธํ์์ผ ํ ํฐ ํํ๋ก ์ ๋ฌํ๋ ๋ฐฉ์์ด๋ค. JWT ๊ธฐ๋ฐ ์ธ์ฆ์ ์ฟ ํค/์ธ์ ๋ฐฉ์๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก JWT ํ ํฐ(Access Token)์ HTTP ํค๋์ ์ค์ด ์๋ฒ๊ฐ ํด๋ผ์ด์ธํธ๋ฅผ ์๋ณํ๋ค.
ํนํ JWT๋ ์๋ฒ์ ์ํ ์ ๋ณด๋ฅผ ์ ์ฅํ์ง ์์๋ ๋๋ Stateless ๊ตฌ์กฐ์ด๋ฏ๋ก, ๋ถ์ฐ ํ๊ฒฝ(์: ์ฌ๋ฌ ๋์ ์๋ฒ, ํด๋ผ์ฐ๋ ํ๊ฒฝ)์์ ๋ฐ์ด๋ ํ์ฅ์ฑ์ ์ ๊ณตํ๋ค.
์ธ์ ๋ฐฉ์์ ๋ชจ๋ ์๋ฒ๊ฐ ๋์ผํ ์ธ์ ์ ์ฅ์๋ฅผ ๊ณต์ ํด์ผ ํ๊ฑฐ๋, Sticky Session๊ฐ์ ๊ธฐ์ ์ ์ฌ์ฉํด์ผ ํ์ง๋ง, JWT๋ ํ ํฐ ์์ฒด์ ์ธ์ฆ ์ ๋ณด๋ฅผ ๋ด๊ณ ์๊ธฐ ๋๋ฌธ์ ์๋ฒ ๊ฐ ์ํ ๋๊ธฐํ๊ฐ ํ์ ์๊ณ , ์๋ก์ด ์๋ฒ๋ฅผ ์ถ๊ฐํด๋ ๋ณ๋ ์ธ์ ๊ด๋ฆฌ ์์ด ๋ฐ๋ก ์ธ์ฆ ์ฒ๋ฆฌ๊ฐ ๊ฐ๋ฅํ๋ค.
์ฆ, JWT๋ Stateless + ๋ถ์ฐ ํ๊ฒฝ ์ ํฉ์ฑ ๋๋ฌธ์, ํ๋ ์น ์๋น์ค์์ ํ์ฅ์ฑ๊ณผ ์ฑ๋ฅ์ ๋์์ ์ก์ ์ ์๋ ์ธ์ฆ ๋ฐฉ์์ผ๋ก ๊ฐ๊ด๋ฐ๋๋ค.

JWT๋ . (dot) ๊ตฌ๋ถ์๋ก ์ด๋ฃจ์ด์ง ์ธ ๊ฐ์ง ๋ฌธ์์ด๋ก ๊ตฌ์ฑ๋๋ฉฐ, ์ค์ ๊ตฌ์กฐ๋ ๋ค์๊ณผ ๊ฐ๋ค.

alg: ํ ํฐ์ ์๋ช
(Signature)์ ์์ฑํ ๋ ์ฌ์ฉํ๋ ํด์ฑ ์๊ณ ๋ฆฌ์ฆ (์: HS256, RS256 ๋ฑ)Header๋ ๋จ์ํ ์ ๋ณด๋ฅผ ๋ด๋ ๋ถ๋ถ์ด๋ฉฐ, ๋ณด์๊ณผ ๊ด๋ จ๋ ๋ด์ฉ์ Signature์์ ์ฒ๋ฆฌ๋๋ค.

JWT์ ์ค์ ๋ฐ์ดํฐ ์์ญ
ํด๋ผ์ด์ธํธ์ ์๋ฒ๊ฐ ์ธ์ฆ์ ์ํด ํ์๋ก ํ๋ ์ ๋ณด๋ฅผ ๋ด๋๋ค
๊ฐ key-value ์์ Claim์ด๋ผ๊ณ ๋ถ๋ฅธ๋ค.
๐จ ์ฃผ์: Payload๋ ์ธ์ฝ๋ฉ๋ง ๋์ด ์์ ๋ฟ ์ํธํ๋์ง ์์ โ ๋๊ตฌ๋ Base64๋ก ๋์ฝ๋ฉ ๊ฐ๋ฅํ๋ฏ๋ก ๋ฏผ๊ฐํ ์ ๋ณด๋ ์ ๋ ๋ฃ์ผ๋ฉด ์ ๋๋ค.

Header์ Payload๋ฅผ ๋น๋ฐํค(secret key)๋ก ์กฐํฉํ์ฌ ํด์ฑ(Signature)ํ ๊ฐSignature ๊ฒ์ฆ์ ํตํด ํ ํฐ ์๋ณ์กฐ ์ฌ๋ถ ํ์ธ ๊ฐ๋ฅHeader์ Payload๋ ๋จ์ ์ธ์ฝ๋ฉ๋ง ๋์ด ์์ด ๋๊ตฌ๋ ์ฝ์ ์ ์์ง๋ง,Signature๋ ์๋ฒ๊ฐ ๊ด๋ฆฌํ๋ ๋น๋ฐํค๊ฐ ์์ผ๋ฉด ์์กฐํ ์ ์๋ค.์ฆ, JWT์ ๋ณด์ ํต์ฌ์ Signature์ ์์ผ๋ฉฐ, ์๋ฒ๋ ํ ํฐ ์์ฒด๋ฅผ ์ ์ฅํ์ง ์๊ณ ๋ ์ ํจ์ฑ์ ๊ฒ์ฆํ ์ ์๋ค.
1. ๋ก๊ทธ์ธ ์์ฒญ
2. ์๋ฒ ๊ฒ์ฆ ๋ฐ ํ ํฐ ๋ฐ๊ธ
์๋ฒ๋ ์ฌ์ฉ์๋ฅผ ๊ฒ์ฆํ ํ, ๊ณ ์ ID, ๊ถํ, ๋ง๋ฃ ์๊ฐ ๋ฑ ํ์ํ ์ ๋ณด๋ฅผ Payload์ ๋ด๋๋ค.
๋น๋ฐํค(secret key)๋ฅผ ์ฌ์ฉํด Header์ Payload๋ฅผ ์กฐํฉํ๊ณ ์๋ช (Signature)์ ๋ง๋ค์ด JWT ํ ํฐ(Access Token)์ ๋ฐ๊ธํ๋ค.
3. ํด๋ผ์ด์ธํธ ํ ํฐ ์ ์ฅ
๋ก์ปฌ ์คํ ๋ฆฌ์ง, ์ธ์
์คํ ๋ฆฌ์ง, ๋๋ ์ฟ ํค ๋ฑ์ ์์ ํ๊ฒ ์ ์ฅํ๋ค.4. ํ ํฐ ํฌํจ ์์ฒญ
Authorization์ ํฌํจ์์ผ ๋ณด๋ธ๋ค.Authorization: Bearer <JWT>
5. ์๋ฒ ๊ฒ์ฆ
Signature๋ฅผ ๋น๋ฐํค๋ก ๊ฒ์ฆํ๋ค.Payload์ ์ ๋ณด๋ฅผ ์ฌ์ฉํด ์์ฒญ์ ์ฒ๋ฆฌํ๋ค.6. ์์ฒญ ์ฒ๋ฆฌ
ํ ํฐ์ด ์ ํจํ๋ค๋ฉด, ์๋ฒ๋ ์์ฒญ์ ์๋ตํ๋ค.
ํ ํฐ์ด ์ ํจํ์ง ์๊ฑฐ๋ ๋ณ์กฐ๋์๋ค๋ฉด, ์ธ์ฆ ์ค๋ฅ๋ฅผ ๋ฐํํ๋ค.
โก ํต์ฌ ํฌ์ธํธ: ์๋ฒ๋ JWT ์์ฒด๋ฅผ ์ ์ฅํ์ง ์์๋ ์ ํจ์ฑ์ ๊ฒ์ฆํ ์ ์์ผ๋ฏ๋ก Stateless ์ธ์ฆ์ด ๊ฐ๋ฅํ๋ค.
์ด๋ ์๋ฒ ํ์ฅ์ฑ ์ธก๋ฉด์์ ํฐ ์ฅ์ ์ด๋ค.
์ฌ์ค ์ด ๋ถ๋ถ์ ๋ํด์๋ ์ ๋ต์ด ์๋ค. ์ ์ฅ ์์น๋ง๋ค ์ฅ๋จ์ ์ด ์๊ธฐ ๋๋ฌธ์ด๋ค.
JWT๋ฅผ ์ ์ฅํ๋ ๋ํ์ ์ธ 4๊ฐ์ง ๋ฐฉ์์ด ์กด์ฌํ๋ค. LocalStorage, SessionStorage, Cookie, ๋ฉ๋ชจ๋ฆฌ(In-Memory) ์ ์ ์ฅํ๋ ๋ฐฉ์์ด ์๋ค.
LocalStorage๋ ๋ธ๋ผ์ฐ์ ์ ๋ฐ์ดํฐ๋ฅผ ์๊ตฌ์ ์ผ๋ก ์ ์ฅํ ์ ์๋ ๊ณต๊ฐ์ด๋ค. JWT๋ฅผ LocalStorage์ ์ ์ฅํ๋ฉด ์ ๊ทผ์ด ๋งค์ฐ ์ฝ๊ณ ๊ตฌํ์ด ๊ฐ๋จํ๋ค๋ ์ฅ์ ์ด ์๋ค.
ํ์ง๋ง ๋ณด์ ์ธก๋ฉด์์๋ ์ทจ์ฝํ๋ค. ์น ํ์ด์ง์ ์ ์ฑ ์คํฌ๋ฆฝํธ๊ฐ ์ฝ์ ๋ ๊ฒฝ์ฐ(XSS ๊ณต๊ฒฉ), ์ ์ฅ๋ ํ ํฐ์ ์ฝ๊ฒ ํ์ทจํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค. ๋ฐ๋ผ์ ๋ฏผ๊ฐํ ์ ๋ณด๋ฅผ ๋ด๊ฑฐ๋ ๋ณด์์ด ์ค์ํ ์๋น์ค์์๋ ์ฃผ์๊ฐ ํ์ํ๋ค.
SessionStorage๋ ๋ธ๋ผ์ฐ์ ํญ ๋จ์๋ก ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ๋ฉฐ, ๋ธ๋ผ์ฐ์ ๋ ํญ์ ๋ซ์ผ๋ฉด ์๋์ผ๋ก ์ญ์ ๋๋ค. LocalStorage๋ณด๋ค ๋น๊ต์ ์์ ํ๊ณ , SPA(Single Page Application) ํ๊ฒฝ์์ ํธ๋ฆฌํ๊ฒ ์ฌ์ฉํ ์ ์๋ค.
ํ์ง๋ง ์๋ก๊ณ ์นจ ์ ๋ฐ์ดํฐ๊ฐ ์ฌ๋ผ์ง๋ค๋ ๋จ์ ์ด ์์ด, ์ฌ์ฉ์ฑ ์ธก๋ฉด์์๋ ๋ค์ ๋ถํธํ ์ ์๋ค. ๋ณด์ ์ธก๋ฉด์์๋ LocalStorage์ ๋ง์ฐฌ๊ฐ์ง๋ก XSS ๊ณต๊ฒฉ์ ์ทจ์ฝํ๋ค.
์ฟ ํค๋ ๋ธ๋ผ์ฐ์ ๊ฐ ์๋์ผ๋ก ์์ฒญ ์ ์ ์กํ ์ ์๋ ์ ์ฅ ๋ฐฉ์์ด๋ค. HttpOnly์ Secure ์ต์
์ ์ฌ์ฉํ๋ฉด ์คํฌ๋ฆฝํธ์์ ์ ๊ทผํ ์ ์์ผ๋ฏ๋ก XSS ๊ณต๊ฒฉ์ ๋ฐฉ์งํ ์ ์๋ค. ๋ํ, ์๋ฒ์ ์๋์ผ๋ก ํ ํฐ์ ์ฃผ๊ณ ๋ฐ์ ์ ์์ด ๊ตฌํ์ด ํธ๋ฆฌํ๋ค.
ํ์ง๋ง ์ฟ ํค๋ CSRF ๊ณต๊ฒฉ์ ์ทจ์ฝํ๋ฉฐ, ํฌ๊ธฐ ์ ํ์ด ์๊ณ ์๋ฒ ์ค์ ์ด ํ์ํ๋ค๋ ๋จ์ ์ด ์๋ค. ๊ทธ๋์ ๋ฏผ๊ฐํ ์๋น์ค์์๋ CSRF ๋์ ์ ๋ต์ ํจ๊ป ์ฌ์ฉํด์ผ ํ๋ค.
๋ฉ๋ชจ๋ฆฌ ์ ์ฅ ๋ฐฉ์์ ๋ธ๋ผ์ฐ์ ์ ์๋ฐ์คํฌ๋ฆฝํธ ๋ณ์์ JWT๋ฅผ ์ ์ฅํ๋ ๋ฐฉ๋ฒ์ด๋ค. ๋ธ๋ผ์ฐ์ ์๋ก๊ณ ์นจ ์ ํ ํฐ์ด ์ฌ๋ผ์ง๊ธฐ ๋๋ฌธ์, ํ์ทจ ์ํ์ ์ต์ํํ ์ ์๋ค. SPA ํ๊ฒฝ์์๋ ํ์ด์ง ์ด๋ ์์๋ ์ ์งํ ์ ์์ด UX ์ธก๋ฉด์์ ๋น๊ต์ ํธ๋ฆฌํ๋ค.
ํ์ง๋ง ์๋ก๊ณ ์นจ ์ ํ ํฐ์ด ์ด๊ธฐํ๋๋ฏ๋ก ์ฌ์ฉ์ ๊ฒฝํ์ด ๋ถํธํด์ง ์ ์๋ค. ๊ทธ๋ฆฌ๊ณ ๋ธ๋ผ์ฐ์ ๋ฅผ ์ข ๋ฃํ๋ฉด ํ ํฐ์ด ์ฌ๋ผ์ง๋ฏ๋ก ์ฅ๊ธฐ ์ธ์ฆ์๋ ์ ํฉํ์ง ์๋ค.
์์ง ๋๋ ์ทจ์ ์ค๋น์์ด๊ณ , ํ์ ์์๋ JWT๋ฅผ ์ด๋ป๊ฒ ์ฌ์ฉํ๋์ง ์ง์ ๊ฒฝํํด๋ณด์ง ๋ชปํ์ง๋ง, ๊ฐ์ธ ํ๋ก์ ํธ๋ ํ์ต์ ํ๋ฉด์๋ ๋ณดํต ์ด๋ ๊ฒ ๋๋์ด ์ฌ์ฉํ๋ค:
Access Token โ ๋ฉ๋ชจ๋ฆฌ(In-Memory)
Access Token์ ์ฃผ๋ก ์งง์ ์๊ฐ ๋์๋ง ์ฌ์ฉ๋๊ธฐ ๋๋ฌธ์, ๋ธ๋ผ์ฐ์ ๋ฉ๋ชจ๋ฆฌ์ ์ ์ฅํด๋ ์ถฉ๋ถํ๋ค. ๋ฉ๋ชจ๋ฆฌ์๋ง ์ ์ฅํ๋ฉด XSS ๊ณต๊ฒฉ ์ ํ ํฐ ํ์ทจ ์ํ์ ์ค์ผ ์ ์์ผ๋ฉฐ, ํ์ด์ง๋ฅผ ์๋ก๊ณ ์นจํ๋ฉด ์๋์ผ๋ก ์ด๊ธฐํ๋์ด ๋ณด์์ฑ์ด ๋๋ค.
Refresh Token โ HttpOnly Cookie
Refresh Token์ Access Token์ ์ฌ๋ฐ๊ธ๋ฐ๋ ๋ฐ ์ฌ์ฉ๋๋ฏ๋ก ์๋์ ์ผ๋ก ์ฅ๊ธฐ๊ฐ ์ ์ฅ๋๋ค. HttpOnly Cookie์ ์ ์ฅํ๋ฉด ์คํฌ๋ฆฝํธ์์ ์ ๊ทผํ ์ ์์ด XSS ๊ณต๊ฒฉ์ ๋ฐฉ์งํ ์ ์๊ณ , Secure ์ต์
๊ณผ HTTPS๋ฅผ ํจ๊ป ์ฌ์ฉํ๋ฉด ์์ ํ๊ฒ ์๋ฒ์ ํต์ ํ ์ ์๋ค. ๋ํ, ์๋ฒ์์ DB๋ Redis ๋ฑ ์ ์ฅ์์ ํ ํฐ ์ํ๋ฅผ ๊ด๋ฆฌํ๋ฉฐ ๊ฒ์ฆํ๊ฑฐ๋ ๋ธ๋๋ฆฌ์คํธ ์ฒ๋ฆฌ๋ฅผ ํตํด ํ์ทจ ์ ๋์ํ ์๋ ์๋ค.
JWT ๊ธฐ๋ฐ ์ธ์ฆ์์ Access Token์ ๋น๊ต์ ์งง์ ๋ง๋ฃ ์๊ฐ์ ๊ฐ์ง์ง๋ง, Refresh Token์ ์๋์ ์ผ๋ก ์ฅ๊ธฐ๊ฐ ์ ํจํ๋ฉฐ Access Token์ ์ฌ๋ฐ๊ธ ๋ฐ๋ ์ฉ๋๋ก ์ฌ์ฉ๋๋ค. ๋ฐ๋ผ์ Refresh Token์ ์์ ํ๊ฒ ๊ด๋ฆฌํ๋ ์ ๋ต์ด ๋งค์ฐ ์ค์ํ๋ค.
RTR๋ โRefresh Token์ ์ฌ์ฌ์ฉํ ๋๋ง๋ค ์๋ก์ด Refresh Token์ ๋ฐ๊ธํ๊ณ , ์ด์ ํ ํฐ์ ๋ฌดํจํํ๋ ์ ๋ตโ์ ๋งํ๋ค.
์ด ๋ฐฉ์์ ํนํ Refresh Token ํ์ทจ ๊ณต๊ฒฉ(Replay Attack)์ ๋๋นํ๊ธฐ ์ํด ์ฌ์ฉ๋๋ค.
โ ๏ธ ๊ณต๊ฒฉ ์๋๋ฆฌ์ค(์ RTR๊ฐ ํ์?)
๊ณต๊ฒฉ์๊ฐ ์ฌ์ฉ์์ Refresh Token์ ํ์ทจํ๋ค๊ณ ๊ฐ์
์ฌ์ฉ์๋ ์ ์์ ์ผ๋ก Access Token ์ฌ๋ฐ๊ธ ์์ฒญ
์๋ฒ๋ ์๋ก์ด Refresh Token์ ๋ฐ๊ธํ๊ณ , ๊ธฐ์กด Token์ ๋ฌดํจํ
๊ณต๊ฒฉ์๊ฐ ํ์ทจํ Token์ ์ฌ์ฉํ๋ ค ํ๋ฉด?
โ ์๋ฒ DB/Redis์์ ์ด๋ฏธ ์ฌ์ฉ๋ ํ ํฐ์ผ๋ก ํ์ โ ์ฆ์ ์ฐจ๋จ
โ ๊ณ์ ํ์ทจ๋ก ์ด์ด์ง๋ ๊ฒ์ ๋ฐฉ์ง
์ฆ, ํ ํฐ์ด ํ ๋ฒ์ด๋ผ๋ ์ฌ์ฉ๋๋ฉด ์ฌ์ฌ์ฉ ๋ถ๊ฐํ๋ฏ๋ก
ํ ํฐ ํ์ทจ ํ ์ฌ์ฌ์ฉ(Replay)์ ์์ฒ ๋ด์ํ ์ ์๋ค.
๋ธ๋๋ฆฌ์คํธ ์ ๋ต์ ๋ ์ด์ ์ ํจํ์ง ์์์ผ ํ๋ Refresh Token ๋๋ Access Token์ ์๋ฒ์ ๊ธฐ๋กํด๋๊ณ , ํด๋น ํ ํฐ์ ์ฌ์ฉ์ ์ฐจ๋จํ๋ ๋ฐฉ๋ฒ์ด๋ค.
JWT๋ ๊ธฐ๋ณธ์ ์ผ๋ก Stateless๋ผ ํ ํฐ ์์ฒด๋ง ์ ํจํ๋ฉด ์๋ฒ ๊ฒ์ฆ์ ํต๊ณผํ๋ค. ํ์ง๋ง ๋ก๊ทธ์์, ํ ํฐ ํ์ (RTR), ํ์ทจ ๋ฑ์ ์ํฉ์์๋ ํน์ ํ ํฐ์ ์ฆ์ ๋ฌดํจํํด์ผ ํ๋ค.
์ด๋ ์๋ฒ ์ ์ฅ์(DB/Redis)์ ๋ฌดํจ ์ฒ๋ฆฌ๋ ํ ํฐ ๋ชฉ๋ก์ ๊ธฐ๋กํด๋๋ ๊ฒ์ด ๋ธ๋๋ฆฌ์คํธ ์ ๋ต์ด๋ค.
๐ซ ๊ณต๊ฒฉ ์๋๋ฆฌ์ค(์ ๋ธ๋๋ฆฌ์คํธ๊ฐ ํ์?)
๊ณต๊ฒฉ์๊ฐ ์ฌ์ฉ์์ ํ ํฐ(Access/Refresh Token)์ ํ์ทจํ๋ค๊ณ ๊ฐ์
์ฌ์ฉ์๊ฐ ๋ก๊ทธ์์์ ํ๊ฑฐ๋, ๋น์ ์ ์ ๊ทผ์ด ๊ฐ์ง๋์ด ํด๋น ํ ํฐ์ ๋ฌดํจํ ์ฒ๋ฆฌ
๋ฌดํจํ๋ ํ ํฐ์ด DB/Redis์ ๋ธ๋๋ฆฌ์คํธ์ ๋ฑ๋ก
๊ณต๊ฒฉ์๊ฐ ํ์ทจํ ํ ํฐ์ผ๋ก ์์ฒญ์ ์๋ํ๋ฉด?
โ ์๋ฒ๊ฐ JWT ๊ฒ์ฆ ๊ณผ์ ์์ ๋ธ๋๋ฆฌ์คํธ๋ฅผ ์กฐํ
โ ์ด๋ฏธ ๋ฌดํจ ์ฒ๋ฆฌ๋ ํ ํฐ์ผ๋ก ํ์ โ ์ฆ์ ์ธ์ฆ ์คํจ
โ ์ถ๊ฐ์ ์ธ ๊ถํ ์์น ๋๋ ๊ณ์ ํ์ทจ ๋ฐฉ์ง
์ฆ, ๋ง๋ฃ ์ ํ ํฐ์ด๋ผ๋ ๋ธ๋๋ฆฌ์คํธ์ ๋ฑ๋ก๋๋ฉด ์ ๋ ์ฌ์ฉํ ์ ์๋ค. ์ด๋ ๋ก๊ทธ์์ / ํ์ทจ / ํ์ ์ ์ฆ์ ์ฌ์ฉ์ ๋ณดํธ๊ฐ ๊ฐ๋ฅํ๋ค๋ ์๋ฏธ๋ค.
JWT ๊ธฐ๋ฐ ์ธ์ฆ์ ์ฐ๋ ํ๋ก์ ํธ๊ฐ ๋ง์์ง๋ฉด์, ๋ง์ ์ฌ๋๋ค์ด Redis๋ฅผ ๋ง์ด ์ฌ์ฉํ๋ค. ๊ทธ ์ด์ ๊ฐ ๋ญ๊น? ๐ค
๋งค ์์ฒญ ๊ฒ์ฆ ์๋๊ฐ ๋น ๋ฅด๋ค
๋ธ๋๋ฆฌ์คํธ๋ Refresh Token ์ํ๋ ๋ชจ๋ ์ธ์ฆ ์์ฒญ์์ ํ์ธํด์ผ ํ๋ค. DB๋ฅผ ๋งค๋ฒ ์กฐํํ๋ฉด ์ง์ฐ์ด ์๊ธฐ์ง๋ง, Redis๋ ๋ฉ๋ชจ๋ฆฌ ๊ธฐ๋ฐ์ด๋ผ ์ด๊ณ ์ ์กฐํ๊ฐ ๊ฐ๋ฅํ๋ค.
TTL(๋ง๋ฃ ์๊ฐ) ๊ด๋ฆฌ๊ฐ ์ฝ๋ค
ํ ํฐ์ ๋ง๋ฃ ์๊ฐ์ด ์๊ธฐ ๋๋ฌธ์, Redis์ TTL์ ์ค์ ํ๋ฉด ์๋์ผ๋ก ๋ง๋ฃ ์ฒ๋ฆฌ๋๋ค. ๋ณ๋์ ์ ๋ฆฌ ์์
์ด ํ์ ์์ด ์ค๋ฌด์์ ํธ๋ฆฌํ๋ค.
Refresh Token Rotation(RTR)๊ณผ ๊ถํฉ์ด ์ข๋ค
ํ ํฐ ์ฌ๋ฐ๊ธ ์ ์ด์ ํ ํฐ์ ์ฆ์ ๋ฌดํจํํด์ผ ํ๋๋ฐ, Redis๋ ์ฝ๊ธฐ/์ฐ๊ธฐ ์๋๊ฐ ๋น ๋ฅด๊ธฐ ๋๋ฌธ์ ์ฆ์ ๋ฐ์ ๊ฐ๋ฅํ๋ค.
๋ถ์ฐ ์๋ฒ ํ๊ฒฝ์์๋ ์์ ์ ์ด๋ค
์๋ฒ๋ฅผ ์ฌ๋ฌ ๋ ์ด์ํ๋๋ผ๋ Redis๋ฅผ ์ค์ ์บ์์ฒ๋ผ ์ฐ๋ฉด ๋ชจ๋ ์๋ฒ๊ฐ ํ ํฐ ์ํ๋ฅผ ๊ณต์ ํ ์ ์์ด, ์ํ ํ์ฅ ํ๊ฒฝ์์๋ ๋ฌธ์ ์๋ค.
๋ค๋ฅธ ์บ์๋ ์ฌ์ฉ ๊ฐ๋ฅํ ๊น?
Redis๊ฐ ๋ง์ด ์ฐ์ด๊ธด ํ์ง๋ง, ์กฐ๊ฑด๋ง ๋ง์ผ๋ฉด ๋ค๋ฅธ ์บ์ ์๋ฃจ์ ๋ ์ธ ์ ์๋ค.
1. Caffeine Cache
JVM ๋ด๋ถ ๋ฉ๋ชจ๋ฆฌ ๊ธฐ๋ฐ ์บ์
์กฐํ ์๋๋ ๋งค์ฐ ๋น ๋ฅด์ง๋ง, ๋ถ์ฐ ํ๊ฒฝ์์ ์ํ ๊ณต์ ๋ถ๊ฐ
๋จ์ผ ์๋ฒ ํ๊ฒฝ์์๋ ์ถฉ๋ถํ ์ฌ์ฉ ๊ฐ๋ฅ
2. Memcached ๋ฑ ๋คํธ์ํฌ ๊ธฐ๋ฐ ์บ์
Redis์ ์ ์ฌํ๊ฒ ๋ถ์ฐ ํ๊ฒฝ์์ ์ํ ๊ณต์ ๊ฐ๋ฅ
TTL ๊ด๋ฆฌ, ๋์ ์ ๊ทผ ์ฑ๋ฅ ๊ณ ๋ ค ๊ฐ๋ฅ
๐ก ์ ๋ฆฌ
JWT๋ Stateless๋ผ ํ ํฐ์ ์๋ฒ์์ ๊ฐ์ ๋ก ๋ฌดํจํํ ์ ์๊ธฐ ๋๋ฌธ์, ํ์ทจ๋ฅผ ์์ ํ ์ฐจ๋จํ๋ ๊ฒ์ด ์๋๋ผ ํผํด๋ฅผ ์ต์ํํ๋ ๋ฐฉ์์ผ๋ก ์ค๊ณํ๋ ๊ฒ์ด ํต์ฌ์ด๋ค.
Access Token๊ณผ Refresh Token์ ์ญํ ์ด ๋ค๋ฅด๊ธฐ ๋๋ฌธ์ ๋์ ๋ฐฉ๋ฒ๋ ๋ค๋ฅด๊ฒ ๊ฐ์ ธ๊ฐ๋ค.
1) Access Token ํ์ทจ ์ ๋์
Access Token์ ์งง์ ๋ง๋ฃ ์๊ฐ์ ๊ฐ์ง๊ธฐ ๋๋ฌธ์
ํผํด๋ฅผ ์ต์ํํ๋ ์ ๋ต์ ์ฌ์ฉํ๋ค.
๋ง๋ฃ ์๊ฐ์ ์งง๊ฒ ์ค์ (5~15๋ถ)
โ ํ์ทจ๋์ด๋ ์ฌ์ฉ ๊ฐ๋ฅํ ์๊ฐ์ด ์ ํ๋จ.
๋น์ ์ ์ฌ์ฉ ํ์ง(IP / UA / ์ง์ญ ๋ณํ ๊ฐ์ง)
โ ๋์ผ ํ ํฐ์ด ๊ฐ์๊ธฐ ๋ค๋ฅธ ํ๊ฒฝ์์ ์ฌ์ฉ๋๋ฉด ์์ฌ ์์ฒญ์ผ๋ก ํ๋จํด Redis ๋ธ๋๋ฆฌ์คํธ์ ๋ฑ๋กํ์ฌ ์ฆ์ ์ฐจ๋จํ๋ค.
Refresh Token ์ฌ๋ฐ๊ธ ์ ์ฐ๊ด๋ Access Token ํ๊ธฐ
โ RTR ๋์ค ์ฌ์ฉ๋ Access Token์ ๋ธ๋๋ฆฌ์คํธ์ ๋ฃ์ด ํ์ฐ์ ๋ง๋๋ค.
๊ฒฐ๋ก ์ ์ผ๋ก Access Token์ ์ฆ์ ๋ฌดํจํ๋ ์ด๋ ต์ง๋ง,
โ์งง์ ๋ง๋ฃ + ์ด์ํ์ ์ฐจ๋จโ์ผ๋ก ํผํด ๊ตฌ๊ฐ์ ์ต์ํํ๋ค.
2) Refresh Token ํ์ทจ ์ ๋์
Refresh Token์ ์ฅ๊ธฐ ๊ถํ์ ๊ฐ์ง๊ธฐ ๋๋ฌธ์ ๋ณด์์ด ํจ์ฌ ์ค์ํ๊ณ , ๋ฌด์กฐ๊ฑด ์๋ฒ ์ ์ฅ์(DB/Redis)๋ก ๊ด๋ฆฌํ๋ค.
๊ทธ๋ฆฌ๊ณ Refresh Token Rotation(RTR) ์ ๋ต์ ์ฌ์ฉํ๋ค.
RTR ๋์ ๋ฐฉ์
ํด๋ผ์ด์ธํธ๊ฐ Refresh Token์ผ๋ก ์ฌ๋ฐ๊ธ ์์ฒญ
์๋ฒ๋ ์๋ก์ด Refresh Token์ ๋ฐ๊ธ
์ด์ Refresh Token์ Redis/DB์์ ์ฆ์ ๋ฌดํจํ
ํ์ทจ ์ํฉ์์์ ํจ๊ณผ
3) ๊ฒฐ๋ก : JWT ํ์ทจ ๋์์ ํต์ฌ
Access Token: ํผํด ์ต์ํ(์งง์ TTL + ๋ธ๋๋ฆฌ์คํธ + ๋น์ ์ ํ์ง)
Refresh Token: RTR๋ก ์ฌ์ฌ์ฉ ๋ถ๊ฐ + ์๋ฒ ์ ์ฅ์ ๊ธฐ๋ฐ ๊ฐ์ ํ๊ธฐ
์ถ๊ฐ ๋ณด์: HttpOnly ์ฟ ํค ์ฌ์ฉ, TLS ๊ฐ์ , ํ ํฐ ๋์ถ ์ง์ ์ต์ํ
ํต์ฌ์ โJWT๋ ๋ฌดํจํ๊ฐ ์ด๋ ต๊ธฐ ๋๋ฌธ์,
์ ์ด์ ํ์ทจ ์ ์ ๋ก ์ค๊ณํ๊ณ , ํผํด๋ฅผ ์ต์ํํ๋ ํ๋ฆ์ ๋ง๋ ๋ค.