Intro
이번 글은 2개의 시리즈로 나누어 Next.js Middleware로 Refresh Token Rotation 만들어보는 경험하기를 주제로 포스팅해보려고 한다.
지난 글을 잠깐 인용하자면 아래와 같다. 왠지 모르겠지만 부트캠프를 하면서 웹 쪽 보안에 꽂혔다. 충격적인 API를 봐서 그런가? 마음 한편에 내버려두었다가 이번에야말로 글을 쓰려고 한다.
이번 프로젝트를 진행하며 한 가지 신경을 썼던 점이라면 바로 비밀번호와 토큰을 암호화하여 저장하는 것이었다. 개인적으로도 그리고 팀적으로도 암호화에 관심이 있었고, 프론트엔드에서도 암호화를 적용하여 조금 더 프로젝트의 완성도를 올려보고 싶었다.
또한 이번 프로젝트에서 사용되었던 API는 다수의 요구사항에 맞춰야 했고 실습의 느낌에 더 가까운 API였기에 백엔드단에서의 암호화에 대한 로직이 전혀 없었고 심지어 특정 API에서는 원본 비밀번호 그대로 응답이 오는 경우도 있었기에 암호화를 적용해야 할 이유가 있다고 판단했다.
여기서 감지한 문제점은 다음과 같다. 첫 번째로 앞서 언급한 것처럼 원본 비밀번호가 노출된다는 것. 두 번째로는 토큰의 만료 시간이 없다는 것이다. 실제 많은 서비스들은 토큰 만료 시간이 있는데 이번에는 그런 로직이 백엔드에서 제공되지 않기에 비밀번호와 토큰을 암호화해야겠다고 생각했다.
사실, 저 경험에서 얻을 수 있었던 사실은 완벽한 보안은 없다이다. 항상 계속 신경 써야 하고, 복잡한 보안적인 부분들을 고민해야 한다.
나는 프론트엔드 개발자의 영역에서 그런 부분을 해결할 수 있을지 고민했었고, 해맑게 브라우저 로직에 암호화 로직을 탑재하였다.
당연히 그러면 안 된다. 브라우저 환경에서는 사용자가 직접 코드를 볼 수 있고, 개발자 도구를 통해 실행 중인 JavaScript 변수나 메모리에 접근할 수 있기 때문이다. 따라서 중요한 데이터를 브라우저에서 암호화해 저장하는 것은 보안적으로 적절하지 않다.
Why & What
보통 프론트엔드 개발하면서 보안은 필수적으로 고려해야 한다. 물론 프레임워크에서 자체적으로 해주는 부분도 있지만, 내용을 알고 사용해야 한다. 이러한 부분에서 개발자가 인지하지 못하면 사용자의 데이터를 탈취당하거나, 공격자가 애플리케이션을 악용할 가능성이 높아진다.
웹 개발에서 흔히 발생하는 주요 보안 취약점들은 다음과 같다.
- XSS (Cross-Site Scripting, 크로스 사이트 스크립팅)
- 악성 스크립트가 사용자 브라우저에서 실행되도록 유도하는 공격 방식이다.
- localStorage, sessionStorage에 저장된 토큰을 탈취할 수도 있다.
- CSRF (Cross-Site Request Forgery, 크로스 사이트 요청 위조)
- 사용자의 인증 정보를 이용해 원하지 않는 요청을 서버로 보내는 공격 방식이다.
- 주로 쿠키 기반 인증을 사용하는 사이트에서 발생하며, 사용자가 로그인된 상태에서 악성 사이트를 방문하면 공격이 수행될 수 있다.
- 쿠키 기반 인증을 사용할 때, CSRF 토큰이 없다면 공격자가 사용자의 세션을 이용할 수 있다.
- 토큰 탈취 및 재사용
- JWT 기반 인증을 사용할 때, Refresh Token이 유출되면 장기간 악용될 위험이 있다.
- 기존 방식에서는 Refresh Token을 한 번 발급하면 일정 기간 동안 계속 사용할 수 있기 때문에, 만약 공격자가 이를 탈취한다면 새로운 Access Token을 지속적으로 발급받을 수 있다.
이러한 보안 문제를 해결하기 위해 다양한 보안 기법을 찾아보았고 그중에서도 가장 흥미로웠던 것이 Refresh Token Rotation(RTR) 기법이었다.
기존의 Refresh Token 방식에서는 한 번 발급된 Refresh Token을 지속적으로 사용할 수 있었다. 만료 기한이 있더라도 Refresh Token의 만료 기간은 보통 길게 부여했던 것으로 기억한다.
하지만 RTR 방식에서는 Refresh Token을 사용할 때마다 새로운 Refresh Token을 발급받고, 기존 Refresh Token은 즉시 폐기된다.
RTR(Refresh Token Rotation) 기법이란?
RTR(Refresh Token Rotation)은 OAuth 2.0의 보안 기법 중 하나로, Refresh Token을 한 번 사용하면 즉시 폐기하고, 새로운 Refresh Token을 발급하는 방식이다. 기존의 Refresh Token 방식과 비교했을 때 보안성이 훨씬 향상된다.
RTR vs 기존 Refresh Token 방식
✅ 기존 방식 (Static Refresh Token 방식)
- Refresh Token을 한 번 발급받으면 유효 기간이 끝날 때까지 계속 사용 가능
- 토큰이 유출되면 공격자가 이를 지속적으로 사용하여 Access Token을 발급받을 수 있음
- 토큰 탈취 시 탐지가 어려움
✅ RTR 방식 (Refresh Token Rotation)
- Refresh Token을 한 번 사용할 때마다 새로운 Refresh Token을 발급
- 기존 Refresh Token은 즉시 폐기되므로 유출되더라도 재사용이 불가능
- 서버는 만약 기존 Refresh Token이 다시 사용되면 이를 감지하고 세션을 차단 가능
이 차이점을 보면, RTR 방식은 Refresh Token 유출로 인한 피해를 원천적으로 차단하는 효과가 있다.
RTR 기법의 장점
🔹 토큰 탈취 방지
- Refresh Token이 한 번 사용되면 새로운 토큰이 발급되고 기존 토큰은 즉시 폐기되므로, 유출된 Refresh Token이더라도 공격자가 사용할 수 없다.
🔹 불법적인 액세스 탐지 가능
- 기존 Refresh Token이 다시 사용되면, 이는 토큰 탈취 가능성이 높다는 신호이다.
- 서버에서 즉시 이를 감지하고 보안 조치를 취할 수 있다.
🔹 사용자 경험(UX) 유지
- 기존 방식에서는 Refresh Token이 유출되면 사용자를 강제 로그아웃해야 했지만, RTR을 사용하면 로그인을 유지하면서도 보안성을 높일 수 있다.
RTR 기법의 단점
🔸 토큰 관리 복잡성 증가
- 기존 방식에서는 Refresh Token을 단순히 저장하면 됐지만, RTR 방식에서는 Refresh Token을 사용할 때마다 새로운 토큰을 발급하고 관리해야 한다.
🔸 추가적인 서버 부하
- 매번 새로운 Refresh Token을 발급하기 때문에, 토큰 관리 로직이 추가적으로 필요하다.
🔸 클라이언트-서버 간 동기화 이슈
- 클라이언트가 새로운 Refresh Token을 받지 못한 상태에서 기존 Refresh Token이 삭제되면, 다시 로그인해야 하는 상황이 발생할 수 있다.
Next
위에서 언급하였듯, RTR은 이론적으로 강력한 보안 기법이다. 기존 Refresh Token 방식의 보안 취약점을 보완하면서도 사용자 경험을 해치지 않는 효과적인 방안처럼 보인다.
다만 개념을 이해하는 것만으로는 실제 환경에서 어떻게 동작하는지 체감하기 어려웠다. 이러한 궁금증을 해결하기 위해 RTR 기법을 시각화하여 보고자 한다. Refresh Token을 검증하고 새로운 토큰을 발급하는 로직을 백엔드에서 처리해야 하고, 프론트엔드에서는 새로운 Refresh Token을 받아 자동으로 상태를 갱신하는 기능이 필요한데,,,, 조금 찾아보니 Next의 미들웨어를 활용해서 얼핏? 그럴 듯? 하게 해 볼 수 있을 것 같아서 해보려고 한다.
원래 한 큐에 글을 쓰려고 했는데 구현한 게 너무 허접스러워서,,,,,,, 포기했다. 커밍쑨
'개발 > 프론트엔드' 카테고리의 다른 글
React와 Vite에서 번들 용량 최적화 방법 (0) | 2024.10.13 |
---|