Project/모익

유저 인증 상태 관리하기

이의찬 2024. 1. 8. 14:40

1. Why?

프로젝트 <모익>에서 회원 관리 및 프론트엔드에서의 보안을 담당하게 되었는데, 그 과정에서 JWT와 OAuth를 사용해서 유저의 인증 상태를 관리했다. 이번 글에서는 어떻게 백엔드와 데이터를 주고받았는지, 그리고 왜 이런 방식으로 구현했는지에 대해서 설명하고자 한다. 

 

만약 네트워크에 대한 배경지식이 없으시다면 아래 링크의 글부터 읽는 것을 추천드립니다.
 

쿠키와 세션 / 네트워크

HTTP W3 상에서 정보를 주고받을 수 있도록 정의된 프로토콜 Connectionless(비연결성) : 요청에 따른 응답을 받고나면 연결을 끊음 Stateless(무상태성) : 클라이언트-서버 관계에서 서버가 클라이언트의

cksxkr5193.tistory.com


2. How?

어떤 선택지가 있는지

1) 세션 기반 인증

인증 정보를 서버의 세션 저장소에 저장

  • 장점
    • 사용자의 인증 정보를 서버에서 안전하게 관리
    • 사용 트래픽이 훨씬 적음

https://developer.okta.com/blog/2017/08/17/why-jwts-suck-as-session-tokens

  • 단점
    • 서버에 상태를 유지해야 함
      • 서버 자원을 사용
      • 세션 불일치 이슈로 인해 수평 확장 시 추가 작업 필요

2) 토근 기반 인증

인증 정보를 토큰에 담아 클라이언트에 저장

JWT(Json Web Token)

  • 웹에서 사용되는 JSON 형식의 토큰
  • JWT는 헤더, 페이로드, 서명으로 구성
    • 헤더와 페이로드는 JSON 기반의 key-value 형태
    • 서명은 헤더, 페이로드, 암호화키와 헤더에서 정의한 해시 알고리즘을 기반으로 생성
      • 모익의 경우에는 SHA-256 사용
  • 장점
    • HTTP의 Stateless(무상태성)을 유지할 수 있음
      • 서버의 확장 시, 수직 확장이 아닌 수평 확장으로도 유지 가능
      • 수평 확장(Scale Out)은 수직 확장(Scale Up) 대비 유연성에서 큰 강점이 있기에 주로 사용됨

      • 서버 부담 없음
  • 단점
    • 토큰 탈취가 가능하기에 보안 문제 발생 가능
    • 이미 발급된 토큰의 관리(만료, 취소 등…)가 어려움

OAuth

  • 장점
    • 복잡한 인증 절차를 외부 서비스에 위임 → 사용자 친화적
  • 단점
    • 외부 서비스에 대한 신뢰가 필요
    • Store에 배포할 경우, 자체적인 회원관리 기능 필요

3. 모익에서 구현한 방식

Moi’c의 로그인 방식

추후 확장성과 서버의 리소스를 고려해  (+ 내가 토큰 관리를 직접 해보고 싶어서) 토큰 기반 인증을 사용했다.

  • RESTful API
  • JWT와 OAuth를 함께 사용
    • JWT
      • Store에 올리기 위해서는 자체적인 로그인이 필수
      • JWT의 문제점 해결
    • OAuth
      • UX 향상

Moi’c에서 구현한 방법

사용자 인증을 위해 Access Token, 자동로그인과 보안을 위해 Refresh Token 사용

  1. 사용자는 로그인을 하면 AccessToken은 Response로, RefreshToken은 Cookie로 받는다.
  2. AccessToken은 항상 header에 추가 되어야 사용자 인증이 가능하다
  3. AccessToken이 만료되었다면 Refresh요청을 보내며 만료된 AccessToken과 RefreshToken이 담긴 Cookie를 서버로 보낸다.
  4. 서버에서는 검증 로직을 거친 후 AccessToken을 발급한다.

Moi’c의 AccessToken

  • 암호화 키 : 팀원들의 이름을 Base64로 인코딩한 문자열
  • 발급자 : moic
  • 유효기간 : 30분
  • Header
    • Key : Authorization
    • value : AccessToken

Moi’c의 RefreshToken

  • 암호화 키 : 팀원들의 이름을 Base64로 인코딩한 문자열
  • 발급자 : moic
  • 유효기간 : 30일
  • Cookie
    • Key : refreshToken
    • value : RefreshToken

검증 로직

AccessToken이 유효할 때

  1. JwtAuthenticationFilter에서 Token 검증
    • 토큰의 유효성 검증
    • 토큰의 만료 여부 검증
  2. Token에서 사용자 ID 추출
  3. 권한 확인 및 서비스 사용

AccessToken이 만료되었을 때

  1. Front-end에 EXPIRED_TOKEN_ERROR*(HttpStatus.*INTERNAL_SERVER_ERROR*, "SE001", "토큰이 만료되었습니다.") 에러 전송
  2. Front-end에서 해당 에러를 받으면 /auth/refresh 로 refresh 요청
    • 이 때 검증을 위해 Body에 만료된 AccessToken과 RefreshToken이 담긴 Cookie를 전송
  3. 서버는 먼저 받은 AccessToken을 검증
  4. RefreshToken도 만료된 토큰인지 확인
  5. 이후 RefreshToken이 서버에서 발급한 Token이 맞는지 Redis에 확인
  6. Redis에 저장된 회원 ID와 만료된 AccessToken에서 추출한 회원 ID가 같은지 확인
  7. 위 검증 과정이 모두 완료되면 AccessToken 재발급
  8. 만약 Refresh도 만료되어 아래와 같은 response를 받는다면 재로그인 요청

이렇게 해서 좋은 점!!

  • AccessToken이 탈취된 경우
    • 짧은 유효기간을 갖고 있어 공격자가 재빨리 사용하지 않으면 의미가 없다
  • RefreshToken이 탈취된 경우
    • refresh 요청은 AccessToken이 있어야 가능하므로 소용이 없다
  • 둘 다 탈취되었다면?
    • 추후에 좀 더 고민해봐야,,,

4. 래퍼런스

https://hudi.blog/session-based-auth-vs-token-based-auth/

 

세션 기반 인증과 토큰 기반 인증 (feat. 인증과 인가)

인증과 인가 세션기반 인가와 토큰기반 인가에 대해 알아보기 이전에 먼저, 인증과 인가가 무엇인지 부터 알아야할 필요가 있다. 인증과 인가를 같거나 비슷한 개념이라고 생각하는 사람들이

hudi.blog

https://inpa.tistory.com/entry/WEB-%F0%9F%93%9A-Access-Token-Refresh-Token-%EC%9B%90%EB%A6%AC-feat-JWT

 

🌐 Access Token & Refresh Token 원리

Access Token & Refresh Token 이번 포스팅에서는 기본 JWT 방식의 인증(보안) 강화 방식인 Access Token & Refresh Token 인증 방식에 대해 알아보겠다. 먼저 JWT(Json Web Token) 에 대해 잘 모르는 독자들은 다음 포스

inpa.tistory.com