JWT는 항상 탈취의 위험이 있다. 이에 따라 필요한 조치들을 구현할 계획이다.
1) 로그인 성공 : 서버측 -> 클라이언트로 JWT 발급
2) 권한이 필요한 모든 요청 : 클라이언트 -> 서버측 JWT 전송
해커는 클라이언트 측에서 XSS를 이용하거나 HTPT 통신을 가로채서 토큰을 훔칠 수 있기 때문에 여러 기술을 도입해서 탈취를 방지하고 탈취됐을 경우 대비 로직이 존재한다.
위와 같은 문제가 발생하지 않도록 Access/Refresh 토큰 개념이 등장한다.
자주 사용되는 토큰의 생명 주기는 짧게(약 10분), 이 토큰이 만료되었을 때 함께 받은 Refresh 토큰(24시간 이상)으로 재발급
Refresh 토큰은, 액세스 토큰이 생명 주기가 너무 짧으니까 로그인을 계속 해야 하는 불편함이 생길 수 있어 만들어두는 장치로 이해하면 된다.
Refresh토큰은 액세스 토큰을 재발급받는 단 한곳의 엔드포인트에서만 사용하기 때문에, 상대적으로 시간을 길게해도 안전하다고 할 수 있다(백프로 안전한건 아니다)
refresh 토큰도 탈취될 수 있다.
우선, 이를 해결하려면
액세스/리프래시 토큰의 저장 위치를 로컬/쿠키에 저장할지 결정해야 한다.
refresh 토큰을 rotate하는 방법도 쓸 수 있다.
로컬 스토리지 -> XSS공격에 취약함(액세스 토큰을 저장)
httpOnly 쿠키 : CSRF에 취약(리프래시 토큰을 저장)
액세스 토큰은 XSS를 클라이언트단에서 최대한 방어할 수 있지만, CSRF 공격의 경우 클릭 한번만으로 단시간에 탈취할 수 있다. 권한이 필요한 모든 경로에 사용되기 때문에 CSRF공격의 위험보다는 XSS 공격을 받는 게 더 나은 선택일 수 있다.(로컬 스토리지는 CSRF공격을 막을 수 있어서)
리프래시토큰은 주로 쿠키에 저장되는데, 쿠키는 httpOnly 설정을 하면 완벽히 방어할 수 있다. CSRF의 경우, 리프래시 토큰의 사용처는 단 하나인 토큰 재발급이다. 회원정보 수정, CRUD에서 CSRF는 취약하지만 토큰 재발급에서는 크게 피해를 입힐만 한 로직이 없다.
액세스 토큰이 만료됐을 때 refresh 토큰을 가지고 서버 특정 엔드포인트에서 재발급을 진행하면, refresh 토큰 또한 재발급해서 프론트 측에 응답하는 방식이다.
로그아웃을 구현하면, 프론트측에서 액세스/리프래시 토큰을 제거한다. 하지만, 이미 해커가 JWT토큰을 복제했다면, 서버측에서는 주도궈이 없기 때문에 방어가 불가능하다. (세션은 상태를 STATE하게 관리해서 서버가 주도권이 있다)
방어방법
Refresh 토큰을 서버 저장소에도 저장을 해서 관리한다. 이 토큰이 저장소 내부에 존재하는지 확인해서, 액세스 토큰에 대한 주도권을 가질 수 있게 된다.
로그아웃을 진행했거나 탈취돼서 피해가 진행되면, 리프래시 토큰을 제거하면 방어가 가능하다.
추가적으로 로그인시 메일 알림도 가능하다. 평소 사용하지 않던 ip나 브라우저에서 접근할 경우, 사용자 계정으로 메일 알림이 발송된다.
이때 내가 아닐 경우 '아니오'를 누르면 서버측 토큰 저장소에서 유저에 대한 리프래시 토큰을 제거하면 된다.