JWT를 이용하여 로그인을 구현하려고 할 때
기본적인 JWT만 이용하면
보안적으로 좋아보이지 않아서
이 보안을 높이는 방법들은 무엇이 있을까?
기본 JWT 방식
--
- 사용자(클라이언트)가 서버에게 로그인 정보를 전달
- 서버는 요청 받은 로그인 정보와 그 외의 정보를 가지고 암호화하여 Token 생성 후 다시 클라이언트에게 응답
- 클라이언트는 이 후 서버에게 요청할 때마다 추가로 Token을 전달
- 서버는 Token을 검증 후 정상이라고 판단하면 로직을 수행
--
Token을 탈취 당하면 탈취자는 무제한으로 Token을 사용할 수 있는데?
[ Access Token에 유효기간 정의 ]
--
우선 JWT 방식은 Stateless(무상태성)이라서 Token을 서버에서 제어할 수가 없다.
그래서 탈취를 당하면 서버에서 조치를 취할 수 없기 때문에
탈취자는 탈취한 Token을 무제한으로 사용할 수 있게 된다.
이를 무제한으로 사용하지 못하게 Token에 유효기간을 설정해준다.
예시로 Token을 발급 받은 시간으로 부터 30분간만 해당 Token을 사용하도록 설정하고
유효기간이 지나면 다시 로그인을 하여 새로운 Token을 받도록 한다.
--
Token의 유효기간이 끝날 때마다 로그인을 해줘야 하는 번거로움이 생기는데?
[ Refresh Token 추가하기 ]
--
Access Token의 유효기간이 끝날 때마다 매번 로그인을 하여 Access Token을 재발급 받는 불편함을 해결 하기 위해
Refresh Token도 추가로 발급해준다.
- Access Token : 사용자 본임임을 인증하는 토큰 (서버에게 요청할 때마다 함께 포함하여 요청)
- Refresh Token : Access Token을 재발급하기 위한 토큰 (Access Token이 만료되었을 때만 서버에게 요청)
Refresh Token은 Access Token이 만료되었을 때 다시 로그인을 하는 번거로움을 방지하기 위한 토큰으로
해당 토큰은 유효기간을 Access Token 보다 길어야 하며 Access Token과 다르게 내부에 로그인 정보와 같은 정보를 담고 있지 않게 하여 탈취 당해도 타격이 없도록 만든다.
다만 정보를 가지고 있지 않는 대신에 Refresh Token은 서버에서 메모리(또는 DB)에 저장하여 보관해야 한다.
그래서 Access Token이 만료되어 Refresh Token을 요청할 때 DB에서 해당 Refresh Token이 있는지 찾아서
Refresh Token을 만들었던 사용자 정보를 가지고 다시 Access Token을 재발급하여 클라이언트에게 응답해준다.
- 사용자(클라이언트)가 서버에게 로그인 정보 전달
- 서버는 요청 받은 로그인 정보를 가지고 Access Token과 Refresh Token을 만들고 Refresh Token은 메모리(또는 DB)에 저장 후 Access Token과 Refresh Token을 클라이언트에게 응답
- 이 후 클라이언트는 서버에게 요청할 때마다 Access Token을 함께 보냄
- 서버는 Access Token을 검증 하고 정상이면 이어서 로직 수행, 만약 유효기간이 지났으면 Refresh Token으로 재요청 보내라고 클라이언트에게 응답
- 클라이언트는 해당 응답을 받고 Refresh Token을 재 요청
- 서버는 Refresh Token을 가지고 메모리(또는 DB)에서 찾은 다음 같이 저장된 회원 정보를 가지고 Access Token을 다시 발급하여 클라이언트에게 응답
- 클라이언트는 재발급 받은 Access Token을 가지고 다시 원래 요청했던 API에 다시 요청
다만 JWT의 장점중 하나는 Stateless(무상태성)으로 session 방식과 다르게 서버에 Token을 저장하지 않아서
상대적으로 부화가 적다고 알고 있는데 Refresh Token을 이제 서버에 저장하게 되어 완벽한 Stateless(무상태성)이라고 할 수가 없어졌다.
그래도 session 방식처럼 요청할 때마다 매번 메모리(또는 DB)를 뒤져서 찾는 것은 아니고
Access Token이 만료될 때만 찾아서 사용하기 때문에 상대적으로 덜 부화된다고 생각한다.
--
Refresh Token이 탈취당하면?
[ Refresh Token Rotation (RTR) ]
--
Refresh Token은 Access Token처럼 매번 요청할 때마다 전달되는 것이 아니라
Access Token을 재발급해야 할 때만 전달이 되는 것으로 Access Token 보다는 탈취 당할 확률이 적다.
그래도 탈취를 당할 수 있다는 것으로 대처를 해줘야 한다.
Refresh Token을 탈취 당하면 탈취자는 Refresh Token을 가지고 새로운 Access Token을 재발급 받아서 자로유롭게 사용할 수 있게 된다.
이 것을 그나마 막기 위해서는 Refresh Token Rotation 방식을 사용한다.
해당 RTR 방식은 Access Token이 만료되었을 때 Refresh Token으로 Access Token을 재발급 시 Refresh Token도 새로 재발급하여 메모리(또는 DB)에 저장했던 이전 Refresh Token과 교체하여 저장하고 클라이언트에 재발급한 Access Token과 Refresh Token을 응답하여 Refresh Token도 새로운 토큰으로 변경해준다.
--
Refresh Token을 탈취하고 탈취자가 Access Token을 발급 받아서 사용하면?
--
탈취자가 기존 사용자보다 먼저 Refresh Token을 가지고 Access Token을 재발급 받으면
탈취자는 새로운 Access Token과 Refresh Token을 발급 받게 되고
기존 사용자가 가지고 있는 Refresh Token은 사용하지 못하게 된다.
이를 막기 위해 생각난 방법들
- 처음 Token을 발급 받았을 때의 사용자 IP을 받아와서 서버에 요청 또는 토큰 재발급 때마다 IP를 확인하여 동일한 IP인지를 확인하고 진행하기
- Access Token이 만료된 것을 확인해야만 Refresh Token으로 새로운 토큰을 재발급 받을 수 있게 하기
- 사용자임을 인증하는 방법들 더 추가하기
1번 같은 경우에는
처음 로그인을 할 때 요청온 IP를 가져와서 Refresh Token을 메모리(또는 DB)에 저장할 때 같이 저장하여 보관하고 있다가
클라이언트가 서버로 요청할 때마다 or 토큰을 재발급 할 때의 IP를 가져와서 첫 로그인 때 저장한 IP와 동일한 IP인지 검증하고 진행한다.
2번 같은 경우에는
만료된 Access Token으로 먼저 요청을 한 뒤에 Refresh Token으로 재발급을 받을 수 있게 하여
탈취자는 Access Token과 Refresh Token 모두 가지고 있어야 하며 Access Token 또한 만료가 될 때까지 기다려야 한다.
3번 같은 경우에는
토큰만 요청하여 재발급 하는 것이 아닌 다른 정보들도 같이 넘겨서 인증 단계를 더 추가하는 방법이다.
이 외에도 다양하고 더 좋은 방법들이 있을 것으로 보인다.
--
JWT에 대해 느낀점
--
JWT 보안에 대해 더 강화할수록 메모리(또는 DB)를 사용해야 하고
이는 JWT의 장점 중 하나인 Stateless(무상태성)를 점차 잃어가게 된다.
완벽한 보안은 없다지만
이렇게 JWT의 단점들을 보안하다보니 점차 Session 방식과 큰 차이가 없어지는 것 같고
어쩌피 JWT의 단점을 보안할 때 결국 Redis와 같이 메모리(또는 DB)를 사용하게 된다.
결국 Redis를 사용하게 되고 RTR 방식으로 매번 토큰을 재발급 받아야 한다면 그냥 세션을 사용하는 것도 괜찮아 보인다.
물론 아직 내가 많이 부족하여 JWT의 진가를 모르는 것일 수 있지만
결국 JWT와 Session 모두 완벽하게 보안을 할 수 있는 방법은 계속 찾아가야 하며
현재 하고 있는 프로젝트에 어울리는 방법을 선택하면 될 것으로 보인다.
--
'Self Q&A' 카테고리의 다른 글
[Spring Boot] API 요청 시 URI에 작성된 id가 본인이 맞는지 어떻게 검사할까? (0) | 2024.05.02 |
---|---|
[Spring Boot] 요청 받을 파라미터(@RequestParam)이 많으면? (0) | 2024.04.28 |
DTO를 깔끔하게 정리하는 방법이 없을까? (0) | 2024.04.25 |
로그인 인증 Session과 JWT 중에 무엇을 사용할까? (0) | 2024.04.17 |