Everyday Dev System

24시간 로그인 유지하기 본문

내배캠 주요 학습/TIL : Today I Learned

24시간 로그인 유지하기

chaeyoung- 2023. 9. 14. 16:28

 

먼저, 로그인을 하면 JWT 토큰을 재발급 해줍니다.

예를 들어 JWT 토큰의 만료 시간이 1시간일 경우, 1시간마다 로그인을 해주어야 합니다.

 

이러한 번거로움과 엑세스 토큰의 탈취를 염려하여 리프레시 토큰을 추가했습니다.

 

 

Refresh Token 도입

쿠키에 토큰을 저장하는 방식을 선택하였고,

쿠키에 만료 시간을 설정하여 웹 브라우저에서 쿠키가 만료가 되면 자동으로 삭제하도록 하였습니다.

이는 웹 브라우저에서 제공하는 기능입니다.

 

 

도입 배경 :

  • 만료 이전의 엑세스 토큰이 탈취되면 이를 활용할 할 수 있다는 문제 발현
  • 보안적인 측면과 사용자의 편의성을 고려하여 Refresh Token을 도입.

목적 :

  • 인증 과정에서 보안적인 측면을 강화
  • 보안적인 측면을 고려함으로써 감소하는 사용자의 편의성 또한 보완
  • 인증 과정의 성능 최적화

 

해결방안 :

1. 엑세스 토큰의 만료 시간 단축

엑세스 토큰의 안정성을 확보하기 위해 유효 기간을 짧게 설정하였습니다.

기간을 짧게 설정하면, 매번 재인증을 거쳐야 하는 번거로움이 발생하여 사용자의 편의성이 감소 합니다.

 

2. Refresh Token의 기간을 길게 설정하여 추가

편의성 감소를 보완하기 위해 refresh Token을 추가하고, 해당 기간을 길게 설정하였습니다.

엑세스 토큰은 1시간, 리프레시 토큰은 24시간으로 설정하였습니다.

  → 브라우저를 닫아도 24시간 자동 로그인이 되며, 24시간이 만료된 이후에는 재로그인이 필요합니다.

Refresh token은 엑세스 토큰을 재발급하는 용도로만 사용됩니다.

 

3. Refresh Token 저장소 선택

엑세스 토큰의 만료 기간을 단축 시킨 만큼 토큰을 재발급해야 하는 과정이 더욱 증가합니다.

매 요청마다 Refresh Token의 검증 절차를 거쳐야 하므로, 데이터 참조가 최대한 빠르게 이루어질 수 있도록 해야합니다.

 

DB 조회 작업이 많으면 많아질수록 미세하게나마 성능 저하가 생길 수 있다고 판단했고,

일반 RDBMS가 아닌 key-value 형태로 저장이 가능한 인메모리 데이터 저장소인 Redis를 활용하였습니다.

 

이를 통해 사용자별 식별자값을 key로, Refresh Token을 value 형태로 저장하였습니다.

Redis는 빠른 입출력 작업을 제공하여 성능을 최적화 할 수 있습니다.

💡 또한 Redis의 캐싱 기능을 활용하는 것도 방법이 될 수 있습니다.

       (캐싱 기능은 추후에 해보고 성능 차이를 비교해볼 예정입니다)

 

 

 

4. 보안 대처 방법

1. XSS 공격 대처

📢 XSS 공격은 게시판이나 웹 메일 등에 자바 스크립트와 같은 스크립트 
코드를 삽입하여 개발자가 고려하지 않은 기능이 작동하게 하는 공격입니다.
Cookies.get('RefreshToken'); 

위 스크립트 코드를 통해 토큰값을 조회가 가능하다는 보안적 취약점을 발견하였습니다.

해당 설정을 할 경우, HTTP 요청 시에만 해당 쿠키를 활용 가능하며,

Javascript 코드를 통해 토큰을 참조 할 수 없습니다.

 

 

2. 스니핑 공격 대처

📢 스니핑이란, 네트워크 송수신 단위인 패킷을 감시하다가 패킷을 캡처하여 내용을 들여다보는 기술을 뜻합니다

이러한 스니핑 공격을 대처하기 위해 쿠키에 setSecure() 속성을 추가하였습니다.

 

서버와 클라이언트가 네트워크를 통해 요청을 송수신하는데, 이러한 요청들을 보낼때 하나의 데이터 단위를 패킷이라고 합니다. 이러한 패킷들을 도청하고 있다가 필요한 데이터의 내용을 참조하는 공격입니다.

Cookie cookie = new Cookie(AUTHORIZATION_HEADER, token); // 쿠키 생성 
cookie.setPath("/"); 
cookie.setMaxAge((int) ACCESS_TOKEN_TIME); 
cookie.setSecure(true); 
res.addCookie(cookie);

 

 

 

케이스별 설명:

먼저, 브라우저에서 쿠키가 만료되었을 때 자동으로 삭제되므로 만료된 토큰으로 시도할 경우는 모두 제외하고 설명하겠습니다.

  • 로그인 시도 시 엑세스 토큰과 리프레시 토큰 동시 발급
    • 먼저, 사용자가 로그인 시, Spring Security 에서 설정한 Filter 단을 거쳐 Jwt 토큰을 발급 받습니다.발급된 해당 토큰을 클라이언트 측에서 쿠키에 담고 있다가, 서버에 요청을 할 때 마다 해당 토큰을 통해 인증 및 인가 처리를 진행할 수 있습니다.
  • 엑세스 토큰 재발급
    • 엑세스 토큰만 없고 리프레시 토큰이 있을 경우: 리프레시 토큰의 검증 절차를 거친 후에 검증 통과 시에는 엑세스 토큰을 재발급하여 인증 및 인가 절차 통과 / 미통과 시에는 토큰 모두 삭제
    • 두 토큰 모두 없을 경우 : 재로그인이 필요합니다.
  • 로그아웃 시 토큰 모두 삭제

 

추가로 고려하면 좋을 사항들

  • 리프레시 만료 시간을 측정하여 로그인 만료 알림 추가
  • Redis에서 리프레시 토큰 만료 시간을 설정해야 합니다.
💡 만약, 자동로그인을 사용하지 않고, 브라우저를 닫으면 재인증을 거치도록 하기 위해서는 설정을 달리 해야합니다. 
브라우저를 닫을 때 쿠키를 삭제하여야 하고, 그럼 세션 쿠키를 생성해야 합니다. 이를 위해서 쿠키에 setMaxAge메서드를 생략하거나 ‘-1’의 음수 값으로 설정하고 만료 시간을 명시적으로 설정하면 안됩니다. 이렇게 하면 쿠키가 세션 쿠키가 되며 브라우저가 닫힐 때 자동으로 삭제됩니다.
그러나, 위와 같이 할 경우 브라우저가 닫히면 웹 브라우저 뿐만이 아니라 서버 DB(Redis)에서도 리프레시 토큰을 삭제하여야 하는데 해당 로직은 더 깊게 고민해봐야 합니다.
  • 웹 브라우저에서 로그아웃 처리를 하지 않고 클라이언트 측에서 아예 쿠키를 삭제했을 때에는 서버에서 토큰을 만료 이전까지 계속 갖고 있는 문제점이 있습니다. 이를 어떻게 처리해야 할까요? 이와 같은 상황에서는 다시 재로그인 하지 않는 이상 리프레시 토큰은 만료되기 전까지 DB에서 삭제되지 않습니다. (만료시간이 지나면 삭제됩니다.)

 

로직 설명:

토큰 만료 설정 시간 → 엑세스: 1시간, 리프레시: 24시간

  1. 로그인 시, 두개를 같이 발급해주고, 쿠키도 만료시간을 설정하면 만료 시간이 지나면 브라우저 자체에서 삭제 처리됩니다.
  2. 엑세스 토큰 혹은 리프레시 토큰이 만료되면 브라우저에서 자동 삭제
  3. 리프레시 토큰이 만료 전이라면 엑세스 토큰 재발급 가능

쿠키 만료시간을 토큰의 만료시간과 동일 설정 → 만료 토큰으로 서버로 요청을 보내는 처리는 고려하지 않아도 됩니다.

setMaxAge() 만료 시간이 아닌 ‘-1’ 을 주면 브라우저를 닫기 전까지는 계속 쿠키가 남아있습니다.

 

📌 요약 : 엑세스 토큰의 시간을 단축하고,
리프레시 토큰을 추가함으로써 24시간 동안 자동 로그인.
브라우저를 닫아도 로그아웃되지 않습니다.
로그아웃을 하거나 쿠키를 삭제하지 않는 이상
로그인 한 이후 24시간 동안은 인증 절차를 다시 거치는 번거로움 해소.