이전에 구현했던 JWT 로그인에 Refresh Token을 추가해보았다. Show 전체 코드는 여기에 올렸다. 1. Refresh Token이란지난 포스팅에선 Access 토큰만 사용하여 인터셉터가 적용된 자원에 접근해보았다. 하지만 이 Access 토큰을 사용하여 요청과 응답을 받는 과정에서 우리는 이 토큰을 탈취당할 수 있다. 토큰은 [헤더]+[페이로드]+[비밀키]로 암호화 되어있지만 성능 좋은 컴퓨터로 비밀키를 알아내면 우리는 모든 정보와 권한을 빼앗기에 된다. 이를 보완하고자 Refresh 토큰의 개념이 사용된다.
해주는 것이 포인트다. 사용자는 Access 토큰을 통해서만 자원에 접근이 가능하고 Refresh 토큰은 소용이 없다. 그럼 언제 Refresh 토큰을 사용하는가? 유효기간이 짧은 Access 토큰이 만료가 되면 Refresh 토큰을 확인하여 검증 후 Access 토큰을 재발급해준다. 즉,
2. 인증 과정위 사진은 로그인으로 설명이 돼있는데 회원가입으로 설명하는 것이 흐름을 알아보기에 조금 더 좋을 것 같아서 조금 바꿔서 설명하겠다.
더 간단한 흐름도로 확인하면 다음과 같다. Refresh 토큰을 통해
또 이러한 JWT 방식은
3. 구현구조우리의 목표는 이 API에 접근하는 것
이는 인터셉터로 막혀있다
회원가입을 하면 Access 토큰과 Refresh 토큰 발행
클라이언트에서 이렇게 토큰을 받는다. Access 토큰을 통해 데이터 요청잘 받아졌다. 시간이 지나 Access 토큰이 만료되면 아무 응답도 받지 못함과 동시에 토큰이 만료됐음을 확인할 수 있다. Refresh 토큰을 사용하여 Access 토큰 재발급Access 토큰은 재발급 된 거, Refresh 토큰은 기존의 것. 근데 Refresh 토큰도 매번 재발급 해주면 보안에 좋다.(Refresh Token Rotation)
Refresh 토큰을 사용하여 Access 토큰을 재발급하는 메소드인데 뭔가 내용이 많아보이지만 사실상 간단하다.
Access 토큰을 재발급 해주는 흐름이다. 또, 이 글을 작성하면서 알게된 사실인데 Refresh 토큰의 페이로드에는 사용자 정보를 넣지 않는게 좋다고 한다. 생각해 보니 그런 것 같다. Refresh 토큰은 유효기간이 길기에 탈취될 수 있고(그 자체로는 뭘 할순 없지만) 탈취되어 내용을 까보면 치명적이진 않더라도 사용자의 정보가 노출되어 버리기 때문인 것 같다. 수정해야겠다. 4. Refresh 토큰에 대한 고찰로그인이나 회원가입을 하고 Refresh 토큰을 클라이언트에게 반환하는 것을 보안상 문제로 인해 지양해야 한다는 주장이 있다. 카카오는 작년 업데이트를 통해 Javascript를 통한 카카오 로그인 기능에서 response 값에서 Refresh 토큰을 제외하기로 했다. https://devtalk.kakao.com/t/javascript-api-sdk-refresh-token/105942 [공지] JavaScript 키를 이용한 API/SDK 사용 시 refresh token 응답 필드 제거 안내 카카오 데브톡. 카카오 플랫폼 서비스 관련 질문 및 답변을 올리는 개발자 커뮤니티 사이트입니다. devtalk.kakao.com 현재 나의 자그마한 뇌로는 구체적으로 어떻게 위협이 될 수 있는지 잘 모르겠다만 아무래도 민감한 정보를 클라이언트에 노출하는 것이다보니 이런 결정을 한 것 같다. 이 뿐만 아니더라도 JWT에 대한 정보를 찾다보면 클라이언트로 발급한 Refresh 토큰을 어디에 저장해야 하는지에 대한 고민을 가진 사람들이 많았다. 그 중 어떤 분이 Refresh 토큰을 토큰 자체로 반환하지 말고 DB에 저장된 곳의 인덱스(정수 or 해시값)만 반환한다면, 클라이언트 측에서는 무의미한 인덱스 숫자만 알게 되는 것이기에 보안적으로 조금 더 좋다는 의견을 제시했다. https://doogle.link/jwt-%ED%98%B9%EC%9D%80-oauth2-%EC%9D%98-refresh-%ED%86%A0%ED%81%B0%EC%9D%84-%EC%96%B4%EB%94%94%EB%8B%A4-%EC%A0%80%EC%9E%A5%ED%95%B4%EC%95%BC-%ED%95%A0%EA%B9%8C/ JWT 혹은 OAuth2 의 refresh 토큰을 어디다 저장해야 할까? | 두글 블로그 요즘 네이버로그인, 카카오 로그인이나 구글 로그인등등 소셜 미디어(Social media) 사용자 로그인 처리를 하다보니 로그인된 상태가 끊임없이 유지되는 것을 구현해야 되더군요. 그러려면 결국 리 doogle.link 상당히 멋진 아이디어라고 생각됐기에 나름대로 구현을 시도해보았다. 결과부터 말하면 실패.
위에서 Refresh 토큰의 페이로드에는 사용자 정보를 담지 않는게 좋다고 했는데 Refresh 토큰 대신 인덱스를 반환하는 이 방식에서는 Refresh 토큰은 DB상에만 존재하게 되니까 상관없을 것 같다. 저 코드대로 해보면 되긴 된다. 근데 이제 매우 안전하지 않다는게 문제다. 구체적으론, 어떤 사용자가 요청한 것인지 확신을 못한다. Attempt 1
But,
Attempt 2
But,
뭔가 처음엔 될 것 같아서 시도해보면 터무니없는 방법임을 알게 된다. 자괴감온다. ㅠㅠ 그래도 고민을 하면서 JWT에 대한 이해는 깊어졌다. 5. 결론그래서 Refresh 토큰을 클라이언트로 보내도 되는가? 안된다면 어떻게 해결하는가? 개인적으로는 Refresh 토큰 그대로 클라이언트로 전송해도 괜찮을 것 같다. 그리고 그게 제일 무난한 방법인 것 같다. 클라이언트 측에서 HTTPOnly 옵션과 Secure 코딩을 적용한 쿠키에 토큰을 보관하는 방법이 여러 기술 블로그들의 주류였다. 그래도 더 개선해보면Refresh Token Rotation 방법이 있다. Access 토큰의 짧은 수명이 다하고 Refresh 토큰을 통해 재발급할때, Refresh 토큰도 바로 재발급 해버리는 것이다. 그렇게 되면 Refresh 토큰의 조작여부를 쉽게 파악할 수 있고 Refresh 토큰 자체도 클라이언트에서 조금 더 안전하다. (계속 바뀌니까) 참고: |