티스토리 뷰

Programming

쉽게 알아보는 서버 인증 2편(Access Token + Refresh Token)

이호연 자유로운 오랑우탄 2018. 7. 29. 02:23



<26$ JWT 티셔츠 >




안녕하세요! 이전 포스팅에는 크게 세션/쿠키 인증, 토큰 기반 인증(대표적으로 JWT)에 대하여 알아보았습니다. 저희가 앱, 웹 혹은 서버 개발을 하면서 꼭 사용하게 되는 인증(Authorization)은 아주 중요합니다. 만일 설계를 잘못했을 시, 회원들의 정보 유출이 일어날 수도 있으니까요.


이번 포스팅에서는 기본 JWT 방식의 강화버전인 Access Token & Refresh Token 방식에 대해 알아보겠습니다. 




Refresh Token?

Access Token(JWT)를 통한 인증 방식의 문제는 만일 제 3자에게 탈취당할 경우 보안에 취약하다는 점입니다.

유효기간이 짧은 Token의 경우 그만큼 사용자는 로그인을 자주 해서 새롭게 Token을 발급받아야 하므로 불편합니다. 그러나 유효기간을 늘리자면, 토큰을 탈취당했을 때 보안에 더 취약해지게 됩니다. 

이때 “그러면 유효기간을 짧게 하면서  좋은 방법이 있지는 않을까?”라는 질문의 답이 바로 "Refresh Token"입니다. 


Refresh Token은 Access Token과 똑같은 형태의 JWT입니다. 처음에 로그인을 완료했을 때 Access Token과 동시에 발급되는 Refresh Token은 긴 유효기간을 가지면서, Access Token이 만료됐을 때 새로 발급해주는 열쇠가 됩니다(여기서 만료라는 개념은 그냥 유효기간을 지났다는 의미입니다.) 


사용 예를 간단히 들어보겠습니다. Refresh Token의 유효기간은 2주, Access Token의 유효기간은 1시간이라 하겠습니다. 사용자는 API 요청을 신나게 하다가 1시간이 지나게 되면, 가지고 있는 Access Token은 만료됩니다. 그러면 Refresh Token의 유효기간 전까지는 Access Token을 새롭게 발급받을 수 있습니다. 




** Access Token은 탈취당하면 정보가 유출되는건 동일합니다. 다만 짧은 유효기간 안에만 사용이 가능하기에 더 안전하다는 의미입니다. 


** Refresh Token의 유효기간이 만료됐다면, 사용자는 새로 로그인해야 합니다. Refresh Token도 탈취될 가능성이 있기 때문에 적절한 유효기간 설정이 필요해보입니다(보통 2주로 많이 잡더군요)



Access Token + Refresh Token 인증 과정




이번에는 과정이 좀 복잡합니다. 차근차근 하나씩 알아봅시다. 빨간색은 1편의 JWT 인증방식에서 추가로 들어간 과정입니다.


1. 사용자가 ID , PW를 통해 로그인합니다.


2. 서버에서는 회원 DB에서 값을 비교합니다(보통 PW는 일반적으로 암호화해서 들어갑니다)


3~4. 로그인이 완료되면 Access Token, Refresh Token을 발급합니다. 이때 일반적으로 회원DB에 Refresh Token을 저장해둡니다.


5. 사용자는 Refresh Token은 안전한 저장소에 저장 후, Access Token을 헤더에 실어 요청을 보냅니다.


6~7. Access Token을 검증하여 이에 맞는 데이터를 보냅니다.


8. 시간이 지나 Access Token이 만료됐다고 보겠습니다.


9. 사용자는 이전과 동일하게 Access Token을 헤더에 실어 요청을 보냅니다.


10~11. 서버는 Access Token이 만료됨을 확인하고 권한없음을 신호로 보냅니다.


** Access Token 만료가 될 때마다 계속 과정 9~11을 거칠 필요는 없습니다.

 사용자(프론트엔드)에서 Access Token의 Payload를 통해 유효기간을 알 수 있습니다. 따라서 프론트엔드 단에서 API 요청 전에 토큰이 만료됐다면 바로 재발급 요청을 할 수도 있습니다.



12. 사용자는 Refresh Token과 Access Token을 함께 서버로 보냅니다.


13. 서버는 받은 Access Token이 조작되지 않았는지 확인한후, Refresh Token과 사용자의 DB에 저장되어 있던 Refresh Token을 비교합니다. Token이 동일하고 유효기간도 지나지 않았다면 새로운 Access Token을 발급해줍니다.


14. 서버는 새로운 Access Token을 헤더에 실어 다시 API 요청을 진행합니다. 




Refresh Token이 들어가면서 과정이 좀 복잡해졌습니다. 하지만 Access Token의 약점을 보완해주기 때문에 보안이 중요한 프로젝트에서는 사용하기를 권장합니다. 




(큰 장점)


기존의 Access Token만 있을 때보다 안전합니다.



(단점)


1. 구현이 복잡합니다. 검증 프로세스가 길기 때문에 자연스레 구현하기 힘들어졌습니다(프론트엔드, 서버 모두)


2. Access Token이 만료될 때마다 새롭게 발급하는 과정에서 생기는 HTTP 요청 횟수가 많습니다. 이는 서버의 자원 낭비로 귀결됩니다. 




저도 현재 프로젝트에  Access Token + Refresh Token 방식을 도입하였습니다. 처음에 구현하기가 좀 힘들 수 있으나 충분히 가치가 있다고 봅니다. 


다음 포스팅에서는 페이스북, 네이버 로그인에 쓰이는 Oauth에 대해 알아보도록 하겠습니다. Oauth도 Access Token + Refresh Token 방식으로 진행되기 때문에 어렵지 않게 이해하실 수 있을겁니다. 짜이찌엔!






[참고]

현재 그랩이라는 닉네임으로 크리에이터 활동을 하고 있습니다. 많은 관심 부탁드립니다 :)

IT 개발자를 이해하기 위한 모든 개발지식 A to Z 자료집

[IT 개발자와 일할 때 필요한 모든 개발지식] A to Z 자료 모음집 By 그랩

장담하건대 이 내용들만 알고 계시면 IT 개발의 전체적인 흐름은 전부 파악한다고 보셔도 무방합니다.

www.notion.so

[유튜브] 그랩의 IT 열차 

그랩의 IT 열차

IT 트렌드 & 지식을 재밌게 전달해주는 그랩입니다👍🏼

www.youtube.com

[뉴스레터] 그랩의 IT 뉴스레터

그랩의 IT 뉴스레터 ARCHIVE

평일 아침 8시. 하루 3분. 새로운 IT 뉴스와 IT 지식을 전달해드립니다. 개발, IT 지식은 그랩의 IT뉴스로 끝! 딱, 3분만 투자하세요!

www.notion.so



댓글
  • 프로필사진 삼정 페북 링크타고 왔습니다. 1편에 이어서 2편도 유익하게 잘 보았습니다. 감사합니다.~ 2018.07.29 12:10 신고
  • 프로필사진 이호연 자유로운 오랑우탄 잘 읽어주셔서 감사합니다!! 더 유익한 글 올리도록 노력하겠습니다 ㅎㅎㅎ 2018.08.11 23:33 신고
  • 프로필사진 화이트채플 Access token 을 갱신할 때 Refresh Token을 전송하는것은 이해했습니다. 그런데 이 때 굳이 만료된 AccessToken을 같이 보내는 이유가 무엇인지 알 수 있을까요?
    그냥 RefreshToken만 전송해도 될것 같은데 그 이유를 알려주시면 감사드리겠습니다!
    2019.03.12 14:40
  • 프로필사진 이호연 자유로운 오랑우탄 안녕하세요! 답변이 늦었습니다.
    새로운 토큰 발행의 관점에서는 굳이 만료된 Access Token을 보낼 필요는 없습니다!! 다만 이는 조건이 추가된 것이라 보면 됩니다.
    1. Refresh Token만 보내면 그때그때 새로운 Access Token을 발급해준다.
    2. 이전의 사용하던 Token을 같이 보내야만 기존의 사용자라는 걸 인식하고 새 토큰을 발행해 준다.

    2019.03.22 00:37 신고
  • 프로필사진 궁금해요 안녕하세요 잘 봤습니다.
    하나 궁금한점이 있는데 RefreshToken을 저장하는 '안전한 저장소'가 정확히 어떤걸 뜻하나요? RefreshToken의 의의가 AccessToken이 탈취되었을 경우에 악의적인 요청 시간을 최소화 하기 위함이라고 이해했는데, 만약에 웹 환경일 경우 마땅한 저장소가 Refresh, Access 둘다 쿠키 말고는 없는것 같습니다(현재 저도 AccessToken을 쿠키에 저장하고 있습니다). 만일 이런 경우 RefreshToken을 어디에 저장 해야 좋을까요? 만일 RefreshToken도 마찬가지로 쿠키에 저장하고, 쿠키가 탈취되었다고 가정하면, AccessToken이 탈취됨과 동시에 RefreshToken도 같이 탈취되서 RefreshToken의 의의가 사라지게 되는데... 어떻게 해결해야할지 너무 궁금합니다
    2019.04.09 09:58
  • 프로필사진 이호연 자유로운 오랑우탄 확인이 늦었습니다T_T
    안전한 저장소의 개념은 웹에서는 크게 통용되진 않는 것 같습니다. 실제로 Access Token & Refresh Token 방식의 장점 자체가 서버에서 Stateless 하게 인증/인가를 처리할 수 있다는 것이고 이는 서버 운영 관점에서 큰 이점이 있습니다. 하지만 세션보다는 클라이언트에게 보안과 관련된 권한을 더 맡기게 되죠.

    동시에 탈취된다면 결국 똑같습니다. 즉 폰을 털리거나 컴퓨터를 털리면 이는 말짱꽝이죠, 다만 Access Token을 통신할 때만 사용하고 Refresh Token은 어딘가에 숨겨둔다면, 이는 Access Token이 탈취되더라도 Refresh Token의 위치는 알 수 없겠죠.

    그리고 저같은 경우는 웹에서 localStorage에 다가 저장을 하긴 합니다만.. local storage의 경우 XSS, cookie의 경우 CSRF에 대한 위험이 있습니다. 아래 글을 참조해보셔도 좋을 것 같습니다.
    https://github.com/IdentityServer/IdentityServer3/issues/2039
    2019.05.19 00:13 신고
  • 프로필사진 hanumoka 글 잘 읽었습니다. 궁금한것이 있어서 질문드려요.
    accesstoken가 탈취 될 경우를 대비해서 refreshtoken으로 accesstoken을 갱신 하는것은 이해가 되지만, refreshtoken이 탈취 당하면 accesstoken을 재 발급 받을수 있는것 아닌가요? 그렇다면 결과적으로 refreshtoken으로 acesstoken을 갱신하는 구조가 accesstoken 단일 토큰 사용을 사용하는 구조에 비해 어떠한 보안상 이점이 있는지 잘 모르겠습니다.

    accesstoken의 경우 통신시 네트워크에 높은 빈도로 노출되지만, refreshtoken은 accesstoken 갱신시에만 요청되기 때문에 상대적으로 네트워크에 노출될 위험이 적어보이기는 하지만....음.. 모호하네요.


    그리고 refreshtoken을 생성할때 db에 저장하는 이유는 무엇인가요? refreshtoken을 생성할때 서버에서 secretkey로 서명?하기때문에 서버에서는 refreshtoken을 따로 db에 저장하지 않더라도 이 토큰의 유효성을 판단 할 수 있지 않나요?
    2019.05.23 08:58
  • 프로필사진 이호연 자유로운 오랑우탄 안녕하세요^^
    첫 번째 답변으로 우선 Access Token, Refresh Token을 개념적으로 분리해보겠습니다.
    Access Token의 경우 짧은 유효시간을 가지고 있으며 서버 단에서 통제가 불가능합니다.
    Refresh Token 은 Access Token을 재발급받기 위한 Key 입니다. 서버 단에서 통제가 가능하며, 클라이언트 단에서는 안전한 스토리지에 저장됩니다.
    JWT를 사용한 토큰 방식으로 인증/인가를 관리할 수 있다는 건 별다른 관리가 필요없이 토큰의 유효성만 검증하면 되는 쉬운 로직입니다. 이는 확장성이 매우 뛰어나서 요새 서버 운용 방식에 딱 맞는 방식입니다.
    그러나 만일 Access Token만 사용하게 될 경우 위의 설명과 같이 서버 단에서 통제가 불가능하다는 단점이고 이는 치명적으로 보안에 악영향을 끼치겠죠. 따라서 Refresh Token 방식을 도입해서 Token에 대한 관리를 가능하게 하고, 동시에 기존에 사용하던 DB 에 저장함으로서 별다른 메모리 기반 스토리지(Redis, memcached etc)를 이용하지 않아도 되기에 장점을 잃지 않게 될 것입니다.

    두 번째의 경우
    Refresh Token이 탈취당하게 될 경우 해당 토큰의 유효기간만큼 Access Token을 무한정 발급받을 수 있다는 단점이 있습니다. 이 때 탈취된 토큰을 무효화하는 로직이 필요한데 유효성 검사 자체만으론 한계가 있습니다. 따라서 DB나 보관이 가능한 스토리지에 Refresh Token을 저장함으로서 관리를 해줄 수 있습니다(만일 Refresh Token을 지우면 클라이언트에서 보낸 토큰과 일치하지 않으므로 무효화되겠죠?)
    2019.05.25 00:33 신고
  • 프로필사진 팽펑 좋은 그림, 깔끔한 도식 감사합니다. 그런데 약간의 의문이 남는데요, 서두에서 말씀하신 것과 그림을 보면 "refresh token은 access token에 보안을 더한 것"으로 느껴집니다. 그렇다면, (1) refresh token을 사용하는 것을 "간략화된 재로그인"이라고 일축해도 될까요? 또한 (2) refresh token으로 1시간마다 새 access token을 발급하는 것과, 24시간의 유효기간을 가진 access token 사이에 어떤 차이가 있는 것인지 한번만 다시 정리해 주시면 좋겠습니다.

    (2)번에 대해 보충하자면, refresh token이 DB에 "저장"되는 듯 한데 이런 방식이라면 access token이 탈취되었다고 할 때, refresh token으로 갱신된 access token을 한 시간 후에 또 탈취하면 되는 것 아닌가요? 암호화 키를 서버에서 한시간마다 바꾸지는 않을 것 같아서요.
    2020.03.01 19:44 신고
  • 프로필사진 팽펑 (2)에 대해서 조금만 더 .... access token 유효시간을 짧게 잡으면 "탈취되더라도 빠르게 만료"된다는게 어떤 의미인지요? access token이 탈취되었다는 말은 secret key가 발각되었다는 의미 아닌가요? 라는 물음입니다 ㅎㅎㅎ

    https://zzossig.io/posts/etc/what_is_the_point_of_refresh_token/

    이 글의 제일 아래 부분에 저랑 비슷한 고민이 있는 것 같아요. 감사합니다.
    2020.03.01 20:19 신고
  • 프로필사진 이호연 자유로운 오랑우탄 안녕하세요. 확인이 늦었습니다.

    1) 넵 기존의 access_token으로만 인증을 진행하다가 refresh_token을 통해 좀 더 안전하게 로그인을 진행한다고 생각하시면 될 듯 합니다.

    2) 토큰이 탈취된 순간부터는 어쩔 수 없이 인증이 뚫릴 수 밖에 없습니다. 토큰이 탈취됐다는 건, 클라이언트에서 직접 탈취됐거나, 아니면 통신 과정에서 탈취를 됐다는 걸 의미합니다. 만일 액세스 토큰이 유효기간이 없다면, 한 번 탈취된 토큰을 계속해서 쓰니까 보안에 치명적일 수 밖에 없겠죠?

    그리고 시크릿 키가 유출되면 절대 안됩니다. 이 부분은 보안을 그냥 냅다 퍼주는 느낌인거죠ㅠ
    2020.03.20 20:44 신고
  • 프로필사진 Hojong 안녕하세요 인증에 대해서 이 글이 제일 이해하기 쉽게 잘 정리되어 있는 것 같아요 여러 글 찾아보았지만 이 글이 제일 많이 도움 되었습니다 감사합니다

    읽으면서 저도 한 가지 궁금증이 생겨 댓글로 남겨봅니다
    refresh token을 DB에 저장하고 요청 시마다 비교하는데, JWT인 이유가 있나요 ?? 궁금해서 여쭤봅니다
    (refresh token verify 대신 DB 값과 비교로 대체할 수 있고, 유효기간도 DB에 저장하여 관리할 수 있으므로 JWT가 아니어도 되지 않나라는 생각이 들었습니다)

    좋은 글 정말 감사합니다

    + 오타 정정 : 14번에 서버 -> 사용자로 수정해야 맞는 것 같습니다. 혹시 헷갈리시는 분 계실까봐
    2020.03.26 22:44 신고
  • 프로필사진 이호연 자유로운 오랑우탄 Refresh Token이 꼭 JWT일 필요는 없습니다! 다만 access token과 유사한 방식으로 처리하는 게 개발 입장에선 수월할 수 있을 거구요. 더불어서 클라이언트, 서버가 결국엔 같이 보관을 하고 있어야하기 때문에, 암호화된 토큰 하나라면 관리하기 수월할 듯 합니다!

    14번은 오타가 있었네요 :) 감사합니다!
    2020.03.29 14:53 신고
  • 프로필사진 Hojong 답글 감사합니다 도움이 되었습니다! 2020.03.30 10:10 신고
  • 프로필사진 jason Secret key를 client와 server가 어떻게 공유하게 되는지 설명 가능하실까요? 2020.03.27 08:48
  • 프로필사진 이호연 자유로운 오랑우탄 Secret Key는 암호화와 복호화를 할 때 쓰이는 키입니다. 그래서 클라이언트는 Secret Key를 알면 안됩니다!
    인증 서버에서만 secret key를 가지고 있어야 하며 이게 유출되면, 토큰을 조작할 수 있기에 꼭 보안을 유지해야 합니다!
    2020.03.29 14:54 신고
  • 프로필사진 리박사사 Secretkey는 서명할때 사용합니다.

    토큰의 변조방지 기능을 하고있습니다.
    탈취후에 만료시간을 늘린다던지, 일련의 변조작업이 진행되었을때라던지 이런것을 방지 할 수 있습니다.

    JWT는 기본적으로 암호화를 하지 않습니다. base64로 디코딩하면 누구나 다 볼 수 있으니, 필요한경우 암호화작업은 별도로 하셔야 합니다.
    2020.08.15 12:28 신고
  • 프로필사진 리프레시토큰은필요없다? 이해가 안 가는 것이 있는데요.
    access토큰이 털릴위험과 refresh토큰이 털릴위험은 100% 동일한데 굳이 refresh를 같이 쓰는 이유가 있을까요. 만약에 해커가 access토큰을 가져갈 능력이 있다면 refresh또한 가져 갈 수 있을 거라고 보는데요 그럼 그 해커는 refresh기간동안 마음껏 재발급을 받으며 사용할 수 있다는 말로도 해석이 됩니다. refresh가 필요한 이유를 아무리 생각해도 모르겠는데요. 저를 설득 좀 해주세요ㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜㅜ
    2020.04.19 20:31
  • 프로필사진 백엔드린이 리프레시 토큰을 같이 쓰는 이유는 제가 알기로는 세션인증에서 슬라이딩 세션이라는 테크닉이 있거든요
    은행같은 경우는 세션 시간이 강제되어 있자나요 그리고 시간이 되면 만료 알림뜨고 연장 물어보는데 이게 다른곳에서는 자동으로 유저가 마우스를 클릭하거나 등등시 자동으로 세션의 만료 시간을 연장 하는 테크닉이라고 아는데 그걸 토큰인증으로 구현한게 리프레시 토큰 이어서 access토큰이 만료되었을까 유저한테 다시 로그인하라고 하지 않고 유저입장에서는 자동으로 로그인 세션이 연장되고 있다고 느끼겠죠 하지만 클라이언트앱은 백엔드 인증서버랑 블로거님이 작성하신데로 토큰 재발급요청하고 있는거구요

    말이 길지만 세션슬라이딩을 토큰 인증으로 구현한거라고 알고 있습니다 한번 구글에서 세션슬라이딩 리프레시 토큰 검색해보세요
    2020.04.22 21:51
  • 프로필사진 VERY FIRE 감사합니다 !!! 2020.05.07 19:42
  • 프로필사진 snapshot 1,2,3편 다 봤는데 정말 쉽게 설명해주셔서 감사합니다!!
    많은 도움이 됐네요!!
    2020.06.03 11:47 신고
  • 프로필사진 ㅁㅁㅁ 잘보았습니다!! 가장 깔끔한 설명이었어요!! 2020.06.11 10:47
  • 프로필사진 ㄱㄱㄱ 궁금한 점이 있습니다. 보통 세션 id 값을 서버에서 세션저장소(redis)에 저장한다고 했을때, session id 뿐만 아니라 사용자의 이름, 생년월일 등 기본적이 정보를 함께 redis에 저장해두지 않나요? JWT를 사용하는 것이 의미가 있으려면 인증을 위해 필요한 redis를 사용하지 않아야 할 텐데, 기존에 사용자의 다른 데이터 사용(캐싱 기능이라던가)을 위해 redis 같은 것을 미리 사용하고 있는 시스템이라면 토큰 기반 인증이 유용한 점이 있나요? 2020.06.26 20:23
  • 프로필사진 JWT 안녕하세요. 잘보았습니다. 인증과정 설명중 5번에서 '사용자는 Refresh Token은 안전한 저장소에 저장 후' 라고 했는데 안전한 저장소라는게 어떤걸 말하는건지 알수 있을까요??? 2020.09.15 17:45
  • 프로필사진 비밀댓글입니다 2020.11.12 16:56
댓글쓰기 폼