이번 프로젝트를 진행하면서 JWT와 관련해 팀원들과 논의한 내용을 기록해 보고자 한다!
안드로이드와 협업하는 과정에서 나누었던 이야기를 크게 3가지로 정리해 보면 다음과 같다.
1. 소셜 로그인에서의 역할 분배
2. 토큰 전달 방식(http only cookie 등), 프론트의 토큰 저장 방식
3. JWT 토큰 재발급
1. 소셜 로그인에서의 역할 분배
지난 프로젝트에서 안드로이드 앱을 출시했을 때, 소셜 로그인은 안드로이드가 처리한 후 서버는 해당 유저의 정보를 받아 저장하는 형식으로 프로젝트를 진행하였다.
이후, 웹 프로젝트를 진행하면서 소셜 로그인에 대해 알아보면서 이번에 구현하고자 했던 소셜 로그인 플로우는 다음과 같았다.
카카오를 예를 들어 설명하면,
1. 프론트가 소셜 로그인을 클릭시 서버로 리다이렉트시켜 Kakao Auth Server에 접근해 인가 코드를 받아온다.
이는 프론트가 직접 Kakao Auth Server에 접근해서 인가 코드를 받아오는 것을 생각했지만 노출될 위험을 줄이기 위해 서버가 처리하는 것이 좋다고 생각했다! 이 방법이 아니어도 프론트가 직접 Kakao Auth Server에서 인가 코드를 받아오는 방법이 존재한다.
2. 받아온 인가 코드로 서버에 POST 요청을 하면, 서버는 해당 인가 코드로 Kakao Auth Server에서 토큰을 반환 받는다.
3. 서버는 해당 토큰을 이용해서 유저 정보를 불러와 가입되지 않았다면 정보를 DB에 저장하고, 이미 가입된 유저라면 앱 내에서 사용 가능한 Refresh Token, Access Token을 발급하여 프론트에 반환해준다.
이렇게 프론트와 서버의 역할을 구분지으면 되겠다 . . ! 라고 생각했지만
안드로이드를 위한 SDK가 존재해 소셜 로그인까지 마친 후 서버에 토큰을 넘겨주는 방식으로 구현할 수 있었다!
자세한 정보:
Kakao Developers
카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.
developers.kakao.com
따라서 이번 프로젝트에서는 소셜 로그인을 안드로이드 sdk를 이용하여 서버는 해당 토큰으로 유저의 정보를 불러와 DB에 저장하고 앱 내의 Refresh Token, Access Token을 반환해 주는 방식으로 구현하고자 한다!
안드로이드 sdk를 이용했을 때 보안상 취약점이 있을지는 한 번 더 찾아봐야겠다 . . !
2. 토큰 전달 방식, 프론트의 토큰 저장 방식
웹으로 프로젝트를 진행할 때에는 Refresh Token을 HTTPS에서 Secure Cookie와 HTTP Only Cookie를 사용한다면, 자바스크립트 기반 공격을 방어할 수 있어 보안상 이점이 있다고 생각했다.
따라서 이와 같이 안드로이드와 협업할 때에도 HTTP Only Cookie를 이용한다면 클라이언트가 해당 쿠키에 접근하지 못하므로 탈취당할 위험이 적어진다고 생각해 이 방식을 택하면 어떨까 고민했다. . .
하지만 안드로이드에서는 토큰을 안전하게 저장할 수 있는 KeyStore나 Encrypted SharedPreferences가 있어 이를 이용하면 로컬 스토리지에 저장하는 것과는 달리 토큰의 보안 문제를 해결할 수 있을 것이라 이야기가 나왔다!
[Android] SharedPreference 암호화? 안드로이드 KeyStore에 대한 설명
SharedPreference 암호화? SharedPreference에 들어가는 데이터는 xml형태로 저장되며, 접근이 가능하다. 그러므로 디컴파일을 통해 접근이 가능하단 뜻이다. 크게 중요하지 않은 데이터를 저장했다면 의
g-y-e-o-m.tistory.com
3. JWT 토큰 재발급
지난 프로젝트에서 JWT 토큰 재발급에 대한 처리를 필터에서 해봤지만 로직이 확실하게 분리되지 못 하고, 인증되지 않은 요청이 들어왔을 때 불필요한 로직이 수행된다는 것을 알 수 있었다.
필터에 재발급 로직을 추가했을 때, 내가 구현했던 로직은 아래와 같은 형태였다.
- 서버에 api 요청이 들어왔을 때 필터에서 access token 유효한지 확인
- 유효하다면 해당 api에 접근 허용
- 유효하지 않다면 refresh token이 있는지 확인
- refresh token이 없다면 401 에러 메시지를 보냄
- refresh token이 있다면 유효한지 검증 후 헤더에 Access token, Refresh token을 재발급해서 반환
이렇게 구현했을 때 로직이 분명하게 나뉘지 않고 Refresh Token과 Access Token의 역할이 명확하지 않아 리팩토링이 필요하다고 생각했는데, 이번 프로젝트를 진행하면서 다시 한 번 생각해 보는 계기가 되었다!
여러 레퍼런스를 찾아보고 팀원들과 이야기한 결과, JWT 인증 필터에서는 Access Token에 대한 유효성 검사와 인증만 수행하고 토큰 재발급 API를 따로 만들어 Refresh Token으로 Access Token과 Refresh Token을 재발급하도록 하는 것이 좋다는 생각이 들었다. Access Token 재발급 방법은 다음과 같다.
Access Token 재발급 방법
- 클라이언트가 서버에 Access Token으로 요청을 한다.
- 서버는 Access Token을 검증하여 만료되었을 경우 토큰이 만료되었다는 메시지를 클라이언트에 전달한다.
- 클라이언트는 서버에 Refresh Token으로 토큰 재발급 API를 호출하여 Access Token 재발급을 요청한다. (/reissue)
- Refresh Token이 유효하다고 검증이 되면 Access Token을 생성해 응답 헤더에 담아 전달한다.
- 만약 Refresh Token도 유효하지 않다면 Refresh Token이 만료되었다는 메시지를 보내 클라이언트는 다시 로그인을 통해 JWT를 발급 받는다.
끝 .
'Trouble Shooting' 카테고리의 다른 글
게시글 테이블과 게시글 이미지 테이블의 연관 관계 설정 (0) | 2023.11.11 |
---|---|
RDB vs NoSQL (0) | 2023.10.20 |
CI/CD 트러블 슈팅 (0) | 2023.07.25 |
벌크연산과 @Modifying / Not supported for DML operations [DELETE] (0) | 2023.02.22 |
Spring Boot 프로젝트 배포 자동화 설정 문제 해결 (0) | 2023.02.04 |