티스토리 뷰
[React] 알아두면 쓸데있는 로그인 기능 구현 지식들✨(ft. JWT 토큰, Access Token, Refresh Token, Cookie, 로컬스토리지)
싱 이 2023. 8. 29. 23:21이번 팀 프로젝트에서 우리는 자체 로그인 기능을 구현해야했다. JWT 토큰 방식을 활용해 Access Token과 Refresh Token을 서버가 넘겨줬다. 그리고 프론트 단에서 토큰들을 쿠키🍪에 저장을 하는 방식으로 구현했다. 프로젝트 전에 동아리 과제를 하면서 시험적으로 프론트와 서버 사이에 토큰을 넘겨보는 작업을 해봤지만, 예상보다 순탄치 않았다.
원래 어떤 이슈를 겪었는지만 쓰려고 하다가 로그인 관련 개념들도 정리했더니 분량이 너무 길어졌다. 에러는 다음 글로 적어야징
👇Set-cookie 헤더로 넘어온 리프레시 토큰이 브라우저 쿠키에 저장이 되지 않아요!에 관한 삽질기👇
🔐 본격적으로 들어가기 전에 로그인 구현에 대해 간단한 설명!
불과 몇달 전, 나는 여느 때와 다름없이 동아리 스터디가 끝나고 새로운 과제를 받았다. 그때 운영진은 우리가 구현해야하는 기능 중 JWT 토큰을 이용해 로그인/로그아웃 기능이 있다고 했다. 당시 내 심정은 아래와 같았다.
당시 나에게 JWT 토큰은 들어는 봤지만 정확히 몰랐던 개념이었다. 그래서 동아리 과제를 할 때 리액트 개념서도 훅훅 넘겨보면서 우당탕탕 개발을 했었는데, 본 프로젝트 때 로그인 및 회원가입 플로우를 내가 담당하면서 좀 더 자세히 공부를 하게 되었다. 나처럼 로그인 기능을 구현해야하는데 개념부터 모르겠다!하는 분들이 조금이라도 이해를 해갈 수 있도록 간단하게나마 로그인 관련 개념 정리를 해보려고 한다.
1️⃣ JWT 토큰이란?
애플리케이션에서 사용자의 인증 과정이 필요하다면, 보통 JWT(JSON Web Token) 방식을 많이 사용한다(물론 세션 id를 이용할 수도 있고, 쿠키 인증을 통해 할 수도 있다). JWT는 인증에 필요한 정보들을 암호화시킨 JSON 토큰으로, 클라이언트의 요청이 있을 경우 서버가 '이 클라이언트는 인증이 되었습니다!' 라고 판단한 후 토큰을 발급해준다. 토큰은 유일한 성격을 띄기 때문에, 서버는 이를 통해 클라이언트를 구분할 수 있다. 바로 이 토큰을 이용해 클라이언트와 서버는 서로 안전하게 정보를 주고 받을 수 있다.
JWT 토큰의 구조를 간단하게 살펴보면 아래 그림과 같이 총 3부분으로 이뤄져있다.
1) 헤더(Header) : 토큰의 타입(여기서는 JWT)과 해싱 알고리즘의 종류가 적혀있다. 해싱 알고리즘은 토큰 검증 시 활용되는 서명 부분에서 사용된다.
2) 내용(Payload) : 서버에서 보낸 사용자 권한 정보와 데이터가 담겨있는 부분이다.
3) 서명(Signature) : 헤더와 내용 부분을 합친 값을 비밀키와 함께 헤더에 있던 해쉬함수를 적용해 생성한 값이다. 생성된 값은 암호화되어있다. 헤더와 내용의 경우 인코딩된 값이기에 외부 조작이 가능하지만, 서명 부분의 경우 비밀키가 유출되지 않는 한 복호화가 불가능하다. 때문에 서명 부분은 토큰의 위변조 여부를 확인할 때 사용이 된다.
JWT 토큰을 활용한다면 다음과 같은 장점이 있다.
- 서버에서 사용자 로그인 정보를 기억하기 위해 소비하는 리소스가 적어진다
- 클라이언트에서 로그인 상태를 관리하기 때문에 서버는 stateless하다. 따라서 서버의 확장성이 높아진다! 서버의 인스턴스가 여러 개로 늘어날 때마다 사용자의 로그인 상태를 공유하고 있을 필요가 없어진다.
그래서 로그인 과정에서도 JWT 토큰인 Access Token을 발급하여 사용자 인증이 가능하도록 한다. 하지만, Access Token만으로 로그인 기능을 구현한다면 한 가지 치명적인 위험성이 있다.
👩💻: 토큰으로 유저 인증 받았으니깐 이제 클라랑 서버는 안전하게 소통할 수 있지롱🎵
😈: 응 그럼 내가 엑세스 토큰 중간에 가로채면 되지롱🎵
👩💻: ...
만약 Access Token만으로 인증을 받았을때, 제 3자가 탈취를 할 경우 보안이 매우 취약해진다는 위험성이 있다. Access Token이 뺏긴다면 토큰을 가지고 있는 사람 누구나 인증받은 유저 행세를 할 수 있기 때문이다. 이를 방지하기 위해 Access Token에 유효시간을 설정하여 일정 시간 이후 토큰이 만료될 수 있도록 설정해준다. 만료된 토큰은 더이상 활용할 수 없다.
토큰의 유효시간을 짧게 설정하면 할수록 제 3자가 토큰을 가로채 남용할 확률을 줄일 수 있다. 하지만 그렇다고 또 너무 짧게 설정을 해버릴 경우 사용자는 그만큼 더 자주 로그인을 해 Access Token을 다시 받아야 하는 번거로움이 있다.
"Access Token의 유효 시간은 짧게 + 사용자가 로그인을 많이 안 해도 되는 방법이 있지 않을까?" 라는 고민 끝에 나온 하나의 방법이 바로 Refresh Token이다.👏
2️⃣ Refresh Token의 등장
Access Token이 유저가 앱에 실제로 접근할 수 있는지 여부를 인증하는 토큰이라면, Refresh Token은 그런 Access Token이 만료되었을 때 재발급, 갱신해주는 토큰이다.
가령 Access Token이 자신의 유효기간인 30분 뒤에 만료가 되었다고 해보자. 이때 Refresh Token은 상대적으로 긴 유효기간을 가지므로, 2주라고 하자. 1) 유저가 로그인을 한 지 30분이 지난 후, API 요청을 날리게 된다면 서버에는 만료된 Access Token이 전달이 된다. 2) Access Token이 만료가 되었다는 것이 클라이언트에 전달이 되었다면, 클라이언트는 서버에게 Refresh Token을 이용해 Access Token 발급 요청을 보낸다. 3) Refresh Token은 아직 유효하기 때문에, 서버는 다시 새로운 Access Token으로 갱신해주고 기존에 받은 API 요청을 처리해준다. 4) 만약에 Refresh Token도 만료가 되었다면 유저는 새로 로그인을 해야한다.
👀 해당 예시에서는 유저가 만료된 Access Token을 가지고 API 요청을 날리는 과정으로 설명이 되었는데, 사실 토큰에 대한 정보를 클라이언트는 모두 알고 있기 때문에 API 요청 전에도 Access Token이 만료가 되었다면 바로 갱신 요청을 할 수도 있다고 한다.
이렇게 토큰 갱신 목적으로 Refresh Token을 이용하면 유효기간이 짧은 Access Token의 단점을 보완할 수 있다.
3️⃣ Access Token, Refresh Token을 이용한 로그인 방식 정리
- 유저가 로그인을 시도한다.
- 클라이언트 측의 로그인 요청을 받은 서버는 Refresh Token과 Access Token을 발급해준다. Refresh Token은 서버의 DB에 저장이 된다. 이는 클라이언트가 가진 Refresh Token과의 일치 여부를 체크하기 위한 용도라고 한다.
- Refresh Token과 Access Token을 전달받은 클라이언트는 저장해놓는다.
- 추후 서버에 API 요청을 보낼 때 유저 인증이 필요하다면 Access Token이 같이 보내지고, 서버에서 해당 토큰의 유효성이 검증된 뒤 요청이 처리된다. Access Token이 만료가 되었다면 Refresh Token을 이용해 갱신을 해주는 과정을 밟게 된다.
- 만약 유저가 로그아웃을 한다면 Access Token과 Refresh Token은 모두 만료된다.
4️⃣ 클라이언트가 토큰들을 저장하는 장소: Cookie vs 로컬스토리지
여기까지 읽었다면 그래도 로그인 과정에서 JWT 토큰이 어떻게 활용이 되는지 조금이라도 이해가 되었길 바란다. 그럼 이제 마지막으로 Access Token과 Refresh Token이 클라이언트의 어디에 저장이 되는지!! 알아보도록 하자. 보통 로컬 스토리지(Local Storage)에 저장이 되거나 Cookie 에 저장이 될 수 있다.
1) 로컬 스토리지
로컬에 도메인 별로 지속되는 간단한 저장소이다. 시간제한이 없고, 브라우저를 종료해도 없어지지 않아 로컬 스토리지의 값을 없애려면 직접 개발자가 삭제를 해줘야 한다. JS 단에서 접근이 가능하다.
특징으로는 딱히 만료기간이 없기 때문에 쿠키보다 장기적으로 데이터를 저장할 수 있다. 그리고 쿠키보다 훨씬 많은 양의 정보를 저장할 수 있다. 그리고 중요한 건 서버와의 HTTP 요청 통신으로 정보를 주고 받는 쿠키와 달리 로컬 스토리지는 클라이언트 쪽에서만 작업이 이뤄지기 때문에 클라이언트와 서버 간 전체 트래픽이 낭비되는 대역폭의 양을 줄일 수 있다. 마지막으로 단순 문자열을 넘어 객체 정보를 저장할 수 있기 때문에, 개발 편의성이 높다. 다만 XSS 공격에 취약하다.
2) 쿠키
브라우저의 쿠키에 저장을 하는 방식이다. 클라리언트가 HTTP 요청을 보낼 때마다 자동으로 쿠키가 서버에 전송이 된다. JS 단에서 접근이 가능하지만, 만약에 서버에서 httpOnly 조건을 붙여서 내용을 넘겨준다면 클라이언트는 아예 접근이 불가능하다. 이는 XSS 위험에 노출된 쿠키의 문제점을 어느정도 보완해줄 수 있는 방법이다.
📌 참고 사이트(별 임티가 달린 건 도움이 많이 된 추천추천글!)
프론트에서 안전하게 로그인 처리하기 (ft. React) ✨
Access Token & Refresh Token 원리 ✨
HTTP 쿠키, 세션, 토큰 뿌시기 + 토큰(JWT) 보안 전략
'💻 Web > CEOS' 카테고리의 다른 글
[이슈] Cookie에 Refresh Token이 저장이 안되는 이슈와 삽질기🍪 (0) | 2023.09.03 |
---|---|
[회고] CEOS 프론트엔드 17기 프로젝트 바리바리 회고 (1) | 2023.08.21 |
[Github] Pull request template 만들기 (0) | 2023.07.02 |
[Next.js 13] CEOS 5&6주차 미션: Netflix 구현하기 (0) | 2023.05.24 |
[React] CEOS 4주차 미션: React-messenger 구현하기 (1) | 2023.05.08 |
- Total
- Today
- Yesterday
- DOM
- 정렬
- JWT 토큰
- 투포인터
- refresh token
- NaCl
- 면접을 위한 CS 전공지식 노트
- cloud
- vpc peering
- TypeScript
- react
- 바리바리
- access token
- Subnet
- 로그인 기능 구현
- 리액트를 다루는 기술
- 프론트엔드
- AWS
- IGW
- 로컬스토리지
- 그리디
- jwt
- ceos
- 쿠키
- route table
- AwsCloudClubs
- 세오스
- VPC
- 이분탐색
- 리액트
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |