일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | 6 | 7 |
8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 |
22 | 23 | 24 | 25 | 26 | 27 | 28 |
29 | 30 | 31 |
- kotest testcontainers
- Invalid property 'principal.username' of bean class
- AccessToken
- TestContainers
- 우아한 테크러닝
- Spring Cloud Gateway
- 소수찾기 java
- 낙관적 락 롤백
- ObjectOptimisticLockingFailureException 처리
- 낙관적 락 재시도
- RefreshToken
- 멀티모듈 테스트컨테이너
- aop
- spring DI
- @transactional
- ObjectOptimisticLockingFailureException
- java
- jpa
- OptimisticLock
- DI
- redissonlock aop
- 백준
- spring aop
- 알고리즘
- springsecurity
- interface
- S3
- netty
- multimodule testcontainers
- 형상관리
- Today
- Total
조급하면 모래성이 될뿐
HttpOnly 쿠키로 토큰 관리 & 재발급 로직 구현 본문
결론
- accessToken, refreshToken 모두 httpOnly 쿠키로 응답했다. (XSS 공격 방지)
- 하지만 refreshToken을 통한 재발급 로직을 구현하기 위해서 httpOnly옵션의 accessToken 쿠키는 서버에서 추가적으로 신경 써주어야 한다. (FE팀에서 조차 accessToken에 접근할 수 없기 때문에 토큰 만료시점을 알 수 없다..)
장점
- XSS 공격 방지할 수 있음.
단점
- 쿠키 관리신경 써야 함
- 서버 로직이 복잡해질 수 있음 (비교적..)
직면한 문제 1
accessToken 쿠키 만료시간.
처음에는 accessToken 쿠키 만료시간을 JWT와 동일하게 주었다. 프론트에서는 토큰 만료 여부를 서버응답에 의존하기 때문에 쿠키가 사라지게 되면 서버에서는 JWT가 만료되었는지 판단할 수 없다.
때문에 accessToken 쿠키의 만료시간을 지정하지 않고 세션 쿠키로 사용했다.
직면한 문제 2
세션쿠키를 사용하다보니 적절한 시점에 쿠키를 삭제해주지 않는다면 만료된 토큰을 가진 쿠키가 계속 남아있게 된다. 이 때문에 토큰 재발급 시 무한호출되는 문제가 있었다.
토큰 재발급 로직은 아래와 같이 처리된다.
여기서 3번. 재발급 요청 시 refreshToken 또한 만료된 경우가 존재할 수 있다. 이 경우 만료된 JWT를 가진 쿠키가 계속 남아있다면 재발급이 불가능한 상태로 모든 API에서는 계속 토큰 만료를 확인하고, 응답하면서 무한호출이 발생한다.
따라서 재발급이 불가능한 경우에는 accessToken 쿠키를 삭제해줘야 했다.
직면한 문제 3
쿠키발급 시 domain 값을 api 호출을 할 수 있는 상위도메인이 될 수 있도록 해야 한다. 이유는 웹 브라우저에서 네트워크 요청 시 쿠키를 포함시키기 위해서다.
웹 브라우저는 쿠키 도메인값의 하위 url인 경우에만 요청에 쿠키를 포함시킨다. 즉, 쿠키도메인이 상위일때만 요청에 쿠키를 포함 시킨다..
- 최초 도메인 값을 신경 쓰지 못했다.
- 그랬더니 배포 후에 로그인 쿠키가 발급해도, FE 서버에서 쿠키가 요청에 포함되지 않았다.
- FE에서 최상위 도메인을 가지고 있는데(service.com) 서버에서 쿠키 발급 시 도메인 값을 지정해주지 않다 보니 쿠키 도메인 값이 요청도메인으로 발급되었다. (domain=service.com)
- api 서버 도메인은 api.service.com이다.
- 그러나 하위도메인에 접근하기 위해서는 쿠키 도메인 앞에. 을 prefix로 붙어주어야 인식한다. (스택오버 플로우 참조)
- .service.com 도메인을 가지는 쿠키를 발급해 주면 된다.
서버 처리방식
- filter에서는 accessToken 쿠키를 검증한다.
- 인증이 필요 없는 API가 있을 수도 있다. 처음에는 이 경우는 토큰을 검증하지 않았다. 그러나 FE로직을 이해하니, 만료되면 이전 API요청을 다시 호출하기 때문에 적용해도 괜찮았다. 유저는 토큰이 만료되었는지 알 수 없다. (직접 개발자 도구를 까보지 않는 이상..)
ex) 인증이 필요 없는 API 요청 시 498을 응답한다면?
- 토큰 재발급 요청
- 성공 -> 유효한 토큰으로 다시 요청
- 실패 -> 만료된 토큰을 가진 쿠키 삭제 -> 서버에서 쿠키자체가 없으면 비로그인 유저로 판단한다.(인증이 필요 없음)
- 재발급 요청 API에서는 토큰 만료시간을 확인하지 않는다. 이 API에서 토큰 만료를 응답하면 프론트 로직에 의해 무한호출이 된다.
- 재발급 요청 시 refreshToken 이 유효하지 않는 경우에는 accessToken을 삭제한다. (maxAge=0으로 발급)
'TroubleShooting > Yapp' 카테고리의 다른 글
Kotlin AOP 따라해보기 (0) | 2023.09.21 |
---|---|
JWT 로그인 구현 (0) | 2023.07.24 |
카테고리 목록 캐싱 처리하기 (0) | 2023.07.12 |