JWT ํ ํฐ ์ด๋์ ์ ์ฅํ๋๊ฒ ์ข์๊น?
ํ๋ก์ ํธ๋ฅผ ์งํํ๋ฉด์ JWT ํ ํฐ์ ์ด๋์ ์ ์ฅํด์ผ ์ข์๊น ์๋ฌธ์ด ๋ค์๋ค.๐ค
์ฐ์ ๋ด๊ฐ ๊ฒฝํํ ํ๋ก์ ํธ์์ ํ ํฐ์ ์ ์ฅํ ์์น๋ ๋ค์๊ณผ ๊ฐ๋ค.
access token
,refresh token
๋ชจ๋ ๋ก์ปฌ ์คํ ๋ฆฌ์ง์ ์ ์ฅaccess token
์ ๋ก์ปฌ ์คํ ๋ฆฌ์ง์ ์ ์ฅ,refresh token
์ ์ฟ ํค์ ์ ์ฅ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)์ ์ ์ฅํ๋ ๋ฐฉ์๋ ์๋ค.
- ์ด ๊ฒฝ์ฐ ์ก์ธ์ค ํ ํฐ์ด ํ์ํ์ง ์์ ์์ฒญ์ ํ ํฐ์ด ์ ์ก๋๋ ๊ฒ์ ๋ง์ ์ ์๋ค.
JWT ํ ํฐ์ ๋ชจ๋ Cookie์ ์ ์ฅํ์ ๋, ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋๊ฐ ์ ๊ทผ ํ ์ ์๋ค. (HttpOnly ์์ฑ)
ํ๋ก์ ํธ์์ access token์ payload
์ ์ ์ Id๋ฅผ ๋ฃ๊ณ , ํ ํฐ์ ๋์ฝ๋ฉํด ์ ์ Id๋ฅผ ์ฌ์ฉํ๋ ค๊ณ ํ๋ ์ ์ด ์์๋ค. ์ด Id๋ฅผ ๊ฒ์๊ธ ์๋ณ์ ์ฌ์ฉํ๊ณ ์ถ์์ง๋ง, HttpOnly ์์ฑ์ ์ค์ ํ๊ธฐ ๋๋ฌธ์ ์๋ฐ์คํฌ๋ฆฝํธ ์ฝ๋๊ฐ ์ ๊ทผํ ์ ์์ด ์ ๋จน์๋ ๊ฒฝํ์ด ์๋ค.๐
์ด๋๋ ๊ทธ๋ฅ API๋ก ์ ์ ์ ๋ณด๋ฅผ ๋ฐ์ผ๋ฉด ๋๋ค. ์ ์ ์ ๋ณด๋ฅผ ์์ฒญํ๋ API๋ฅผ ๋ณด๋ด๋ฉด(๋ก๊ทธ์ธ ํ access token์ด cookie์ ์ ์ฅ๋์ด ์๋ค๊ณ ๊ฐ์ ) ์์ฒญ ํค๋์ ์ฟ ํค๊ฐ ํฌํจ๋๊ณ , ์๋ฒ์์๋ ํ ํฐ์ ๋ฐ์ ๋์ฝ๋ฉํ๋ค. ๊ทธ๋ฆฌ๊ณ payload
์ ์๋ ์ ์ Id๋ฅผ ๊ฐ์ง๊ณ ์์ฒญ์ ๋ณด๋ธ ์ฌ์ฉ์๊ฐ ๋๊ตฌ์ธ์ง ํ๋จํ๋ ๊ฒ์ด๋ค.
ํ ํฐ ๋์ฝ๋ฉ์ ๊ผญ ํด๋ผ์ด์ธํธ์์ ํด์ผํ๋ค๋ ์๊ฐ์ด ๋๋ฌด ์ปธ๋ ๊ฒ ๊ฐ๋ค.