본문 바로가기
WEB

[WEB] JWT 알아보기 (Json Web Token)

by BK0625 2023. 9. 14.
반응형

그 전에는사용자 인증을 하기 위해서 쿠키와 세션을 주로 사용했었다. 하지만 요새 트렌드는 JWT로 인증을 구현하는 것 같다. JWT를 알아보고 이게 왜 만들어졌는지 어떤 구조로 되어 있는지를 알아보자.

 

jwt란?

 

Cookie와 Session

 

먼저 기존의 인증 방식을 살펴보자.

 

쿠키는 클라이언트가 웹 사이트에 접속할 때 그 사이트가 사용하게 되는 일련의 작은 기록 파일이라고 할 수 있다. Key Value 형식의 문자열 형태로 저장이 되며 서버가 클라이언트에 정보를 전달핼 때 저장하고자 하는 정보를 응답 헤더에 저장하여 전달하게 된다. 즉 브라우저에 저장되어 사용하는 작은 텍스트 파일이라고 할 수 있다.

 

 

쿠키는 인증 과정에서 로그인을 했을 때 Set-Cookie의 형태로 반환을 받고 로그인이 필요한 요청을 할 때 마다 받은 쿠키를 던져 요청을 하는 동작구조를 가지게 된다.

 

 

하지만 큰 문제가 있어 현재는 쿠키를 인증에 온전히 사용하지는 않는데 그 이유는 다음과 같다.

 

  • 쿠키는 아이디나 비밀번호 같은 민감한 정보까지 저장하기 때문에 노출이 되었을 때 보안이 좋지 않다.
  • 웹 브라우저마다 쿠키에 대한 지원 형태가 달라 브라우저 간 공유가 불가능하다.
  • 사용자의 브라우저에 저장되기 때문에 쉽게 탈취 당할 수 있다.
  • 쿠키의 사이즈는 4KB로 제한되어 있어 충분한 데이터를 담지 못 할 수도 있다.
  • 서버는 매번 아이디, 비밀번호 등을 받아서 인증을 해야 하는 불편함이 있다.

 

그래서 주로 사용됐던 것이 세션이다.


세션은 특정 인증 정보는 서버가 가지고 있고 그에 대한 일종의 열쇠, 즉 세션 ID를 클라이언트의 특정 저장소에 저장하여 사용한다. (스프링 + 톰캣에서 세션을 사용하면 브라우저에 JSESSIONID가 발급되어 있는 것을 볼 수 있다.) 개인에 대한 민감한 정보를 서버에서 가지고 있기 때문에 보안 문제가 보완되었으며 매번 로그인 시 아이디, 비밀번호를 작성해서 전달할 필요가 없다. 클라이언트가 가지고 있는 세션 ID와 서버에 있는 세션 저장소에 세션  ID가 있는지 확인하고 있다면 인증이 완료되는 방식이다.

 

 

만약 보완에 문제가 생기면 (Session ID를 탈취당한다던지) 그냥 세션 저장소를 전부 지워버리면 된다. 이건 단점이 될 수도 있는데 세션 저장소에 문제가 생기면 말 그대로 인증체계가 아예 작동하지 않을 수 있다는 것이다.

 

 

또 다른 단점은 세션 저장소가 필수적으로 존재하기 때문에 이를 사용하기 위한 비용이 많이 들며 사용자가 많아질수록 메모리를 많이 차지하게 되고 모든 요청에 따라 세션 저장소를 조회해야 하는 점이 있다.

 

 

이런 과정에서 더 좋은 방법이 없을까 하며 나온 것이 JWT이다.

 

 

 

JWT

JWT는 Json Web Token의 약자로 전자 서명된 URL-state의 json 방식의 인터넷 표준 인증 방식이다. 인증에 필요한 정보들을 Token에 담아 암호화시켜 사용하는 것인데 즉 서명된 토큰이라는 것이다. 공개/개인 키를 사용하여 토큰에 서명할 경우 서명된 토큰은 개인 키를 보유한 서버가 이 서명된 토큰이 정상적인 토큰인지 인증할 수 있다.

 

 

JWT의 구조

JWT의 구조는 각각의 구성요소가 . 으로 구분되어 있으며 구성요소는 Header, Payload, Signature가 있다.

 

-Header

header에는 보통 토큰의 타입이나, 서명 생성에 어떤 알고리즘이 사용되었는지 저장한다. 위 같은 경우는 jwt 타입의 토큰이고 HS256알고리즘이 적용되어 암호화 되어있다고 할 수 있다.

 

 

-Payload

 

 

Payload에는 보통 Claim이라는 사용자에 대한, 혹은 토큰에 대한 property를 key-value 형태로 저장한다. 이 안에 Claim 값을 어떤 거 넣는지는 개발자 마음이다. jwt 표준 스펙장 key의 이름은 세글자이지만 딱히 큰 상관은 없다. 위 이미지의 iat(토큰 발급 시간)과 exp(토큰 만료 시간)이 jwt 표준 스펙 중 하나이다.

 

 

다만 중요한 것은 여기에 민감한 정보를 담지 않는 것이다. header와 payload는 json이 디코딩 되어있을 뿐이지 특별한 암호화가 된 것이 아니다. 따라서 jwt를 가지고 있으면 누구나 거기에 담긴 정보를 알 수 있다.

 

 

https://jwt.io/

 

JWT.IO

JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.

jwt.io

 

 

위 사이트에 가면 이런 식으로 디코딩해서 다 볼 수 있기 때문에 아이디나 비밀번호, 기타 개인 정보는 담지 않는게 좋다. 그냥 단순히 식별을 하기 위한 정보만을 담아야 한다.

 

 

header와 payload도 암호화를 통해 감추어야 하지 않겠냐는 생각이 들 수 있지만 암호화가 많은 리소스를 사용하기 때문에 신중하게 사용해야한다. 민감한 정보를 암호화 하게 되면 매 http 요청마다 한 번의 복호화가 추가되기 때문이다. 따라서 유출 되었을 때 큰 상관이 없는 정보만 담는 것이 기본 스펙이 되는 것이다.

 

-Signature

 

서명 부분이다. header와 payload를 보여줄 때에는 인코딩 되어 있는 값들을 jwt에 담겨있는 것처럼 디코딩된 상태를 사용한다. header를 디코딩한 값, payload를 디코딩한 값을 합치고 이를 your-256-bit-secret(서버에 있는 개인키)를 가지고 암호화된 상태이다.

 

 

즉 서버에 있는 개인키가 없다면 다른 클라이언트는 임의로 복호화 할 수가 없다.

 

 

복호화 하는 과정은 다음과 같은데

 

  1. JWT 토큰을 클라이언트가 서버로 요청과 동시에 전달한다.
  2. 서버가 가지고 있는 개인키를 가지고 Signature를 복호화한 다음 base64UrlEncode(header)가 JWT의 header 값과 일치하는지, base64UrlEncode(payload)와 일치한 지 확인하여 일치한다면 인증을 허용한다.

 

만약에 클라이언트가 payload에 담긴 식별자가 변조된 jwt로 요청을 한다면 서버가 애초에 발급했던 Signature 안에 payload와 다르기 때문에 인증이 되지 않는다.

 

 

jwt의 장점은 다음과 같다.

 

  • 이미 토큰 자체가 인증된 정보이기 때문에 세션 저장소와 같은 별도의 인증 저장소가 필수가 아니다.
  • 세션과는 다르게 클라이언트의 상태를 서버가 저장하지 않아도 된다.
  • Signature를 공통 개인 키 암호화를 통해 막아 두었기 때문에 데이터에 대한 보완성이 늘어난다.
  • 다른 서비스에 이용할 수 있는 공통적인 스펙으로 활용할 수 있다.

 

물론 한계점도 있다

 

  • 쿠키, 세션 때와는 다르게 base64 인코딩을 통한 정보를 전달하므로 전달량이 많기 때문에 네트워크 전달시 많은 데이터 양으로 부하가 생길 수 있다.
  • Payload에는 암호화가 되어있지 않기 때문에 민감 정보를 저장할 수 없다.
  • 토큰이 탈취당하면 만료될 때까지 대처가 불가능하다.

 

이 중 세 번째가 심각한 문제를 야기할 수 있다. 따라서 나온 해결 책은 만료시간을 짧게 가져가는 것이다. 1시간 정도의 짧은 토큰을 저장한다면 만약 토큰이 탈취 되어도 짧은 시간만 유효하기 때문에 최소한의 보안성을 가져갈 수 있다. 물론 유효시간이 짧아지면 사용자가 불편을 느낄 수 있기 때문에 그에 대한 보완책 역시 있다.

 

-Sliding Session

만약 내가 이 글을 쓰는 동안 짧은 만료 시간으로 인해 인증이 취소되어 글이 날아간다면 모니터를 거꾸로 접어버릴지도 모른다. Sliding Session을 사용하게 되면 글쓰기, 결제 등과 같은 특정 action을 유저가 행동하였을 때 새롭게 만료시간을 늘린 JWT를 다시 제공함으로써 만료시간을 연장하여 보완하는 방법이다.

 

다만 접속이 단발성으로 일어난다면 Sliding Session으로 연장시켜줄 수 없는 상황이 생기고, 너무 긴 AccessToken을 발급시켜준 상황이라면 Sliding Session으로 무한정 사용하는 상황이 발생할 수 있다.

 

-Refresh Token

아마 주로 사용되는 방법일텐데 JWT를 처음 발급할 때 Access Token과 함께 Refresh Token을 함께 발급하는 것이다. 비교적 긴 시간의 만료시간을 가진 Refresh Token은 말 그대로 Access Token을 Refresh 해주는 것을 보장한다. 만약 Access Token이 만료된 것을 클라인트가 인지하거나 서버로부터 만료된 것을 확인 받았다면 Refresh Token으로 서버에게 새로운 Access Token을 발급하도록 요청하여 발급받는 방식이다. 

 

 

공부하면서 정리한 내용입니다. 모든 지적 감사히 받겠습니다:)

 

 

 

반응형

'WEB' 카테고리의 다른 글

[Redis] Redis란?  (0) 2023.09.11
[WEB] 웹서버와 WAS의 차이  (0) 2023.07.19
[WEB] URL과 URI의 차이  (0) 2023.07.13
HTTP와 HTTPS, SSL  (0) 2023.01.19