지식&개념

토큰에 대한 고민

muyeon 2024. 4. 22. 19:40
인증 및 인가를 할 때 선택지는 쿠키, 세션, 토큰 정도가 있다. 주로 토큰방식을 사용하며 JWT 를 사용한다.
왜 토큰을 사용할까? 토큰이 정말 안전할까? 등 나의 생각을 정리해보려고 한다.

 

 


 

JWT 는 어떻게 구성이 되어 있을까?

 

점(.)을 기준으로 헤더.페이로드.시그니쳐 로 구분된다.

 

헤더에는 토큰의 유형 + 해싱 알고리즘이 들어있다.

 

페이로드는 토큰에서 사용할 정보(클레임)이 들어있다. 이 클레임은 json 객체이다. 

클레임은 토큰 정보를 표현하기 위해 정해진 종류의 데이터이다.

물론 사용자가 정의해 비공개 클레임을 만들 수도 있다.

 

시그니쳐는 토큰을 검증하기 위한 것들이 들어간다.

헤더와 페이로드를 base64로 인코딩한 후 비밀키를 이용해 헤더에서 정의한 알고리즘으로 해싱해 다시 base64 로 인코딩한다.

 


 

페이로드에 들어갈 내용과 들어가지 말아야 할 내용은 무엇이 있을까?

 

페이로드는 사용자를 식별할 수 있는 정보가 필요하다.

공식 클레임에서는 토큰 발급자, 토큰 제목, 토큰 대상자, 토큰 만료 시간, 토큰 활성 날짜, 토큰 발급 시간, 토큰 식별자로 사용하고 이중에서 sub의 경우 유니크한 값인 이메일을 보통 사용한다.

페이로드에 담기면 안되는 정보는 사용자의 민감한 정보이다.

비밀번호, 개인번호 등 인데 이를 페이로드에 넣는다면 손쉽게 토큰에서 비밀번호를 확인할 수 있는 위험한 상황을 초래한다.

이는 시그니쳐가 되어있다고 해도 내용이 암호화되지 않아 누구나 페이로드를 읽을 수 있으니 꼭 주의해야한다.

 


 

토큰을 왜 사용할까?

 

주로 인증과 권한 부여에 사용한다. 

인증에는 여러 방식이 있지만 토큰은 이들의 단점을 해소하기 위해서 사용한다. 

다른 방식에는 쿠키와 세션이 있다.

 

쿠키는 stateless 하며 주체가 클라이언트에 있어 훼손되고 변질될 수 있어 위험하다.

그 대안으로 세션도 괜찮은 녀석이다. 쿠키와 다르게 stateful 하다. 서버측에 저장되기에 쿠키와 다르게 훼손과 변질이 어렵다.

이는 장점이기는 하나 단점이 되기도 한다.

서버에서 관리되는 만큼 서버의 일이 더 늘어나고 부하가 발생하면 곤란해진다.

때문에 토큰은 쿠키와 세션을 보완하기위해 사용한다.

 

토큰은 stateless 하며 서로를 알아보기 위해 토큰을 사용한다. 입장 티켓 같은 느낌이라고 생각하면 좋다. 서버는 사용자의 신원을 확인 후 고유한 토큰을 발급한다. 이후 요청마다 토큰을 검증하며 이를 통해 신원을 재확인 할 필요없이 보안성을 유지할 수 있기에 사용한다.

 


 

그럼 보안을 위해서 진짜 안전해?

 

쉽게 탈취될 수 없도록 HTTPS 프로토콜을 사용해 안전하게 전송해야한다.

하지만 정말 이걸로 된걸까? HTTPS 프로토콜을 사용했는데도 어찌저찌 탈취되었다면?

 

"토큰의 만료시간을 적절하게 조절해요"가 일반적인 답 일 것 같다. 이렇게 한다면 사용자가 자주 로그인 해야하는 불편함을 겪을 것이다.

나 또한 도메인 호스팅 사이트인 "가비아"가 토큰 만료시간이 굉장히 짧아 정말 불편했었다.

 

"그러면 리프레쉬 토큰을 발급해요!"

 

리프레쉬 토큰으로 사용자 경험은 개선할 수 있다고 생각한다. 하지만 이는 탈취당했을 경우의 대안은 아니라고 생각한다.

클라이언트는 두가지 토큰을 모두 가지고 있을 텐데, 마찬가지로 리프레쉬 토큰도 탈취당할 수 있다.

이는 stateless 한 방식의 딜레마인 것 같다.

 

완화할 수 있는 방법은 서버가 토큰을 알고있어야 한다. 즉 stateless 한 JWT 의 장점을 상실하는 것이다.

사용자가 로그아웃 요청시 리프레쉬 토큰을 무효화해서 새로운 토큰을 발급받지 못하게 하거나, 토큰 블랙리스트를 관리하는 방법이 있다.

이렇게 한다면 매 요청마다 블랙리스트임을 확인해 위험을 줄일 수 있다.

 

질문으로 돌아가면 결국 안전하다는 건지 뭔지 애매하다.

애매할 수 밖에 없다. 완벽한 보안은 존재하지 않고, 최소화만 가능할 뿐이다. 대개 보안성을 높이면 성능이 하락한다. 

프로덕트의 상황에 따라 이를 적절하게 결정하는 것이 개발자의 일이라고 생각한다.