본문 바로가기
NodeJS, NPM, Koa

JWT(Json Web Token)와 세션관리에 대해서 알아보자

by Developer88 2020. 5. 18.
반응형

오늘은 JWT(Json Web Token)와 세션관리에 대해서 정리해 보도록 하겠습니다.

 

1. JSON Web Token(JWT)

JWT는 토큰 정보와, 해당 토큰이 유효함을 증명할 수 있는 signature가 포함되어 있는 토큰인데요.

 

JWT는 Header, Payload, 그리고 Signature로 구성되어 있는데요.

Header는 signing algorithm과 어떤 타입의 토큰인가로 구성할 수 있는데요.

비대칭인 RS256과 같은 알고리즘을 쓸 수도 있고, HS256을 쓸 수도 있겠지요.

{  
 "alg": "HS256",   
 "typ": "JWT"
}

 

Payload에는 유저에 대한 상태나 정보등을 담을 수 있는데요.

아래와 같은 정보들을 담을 수 있습니다.

{
 "sub": "77823323",
 "name": "Big Park",
 "iat": 1516239122
}

 

마지막은 signature는 아래와 같이 구성할 수 있습니다.

HMACSHA256(  
 base64UrlEncode(header) + "." +  
 base64UrlEncode(payload),  
secret)

 

https://jwt.io/ 에 가면 아래와 같이 실제로 인코딩된 값을 볼 수 있습니다.

 

 


2. JWT 구현

2-1. JWT라이브러리 설치

JWT라이브러리는 www.jwt.io/를 참고하면 알 수 있는데요.

Nodejs에서는 jsonwebtoken 모듈을 사용할 수 있습니다.

 

아래 npm명령어로 jsonwebtoken을 설치해 줍니다.

npm install --save jsonwebtoken

 

해당 패키지에 대한 공식git허브 페이지는 아래와 같습니다.

https://github.com/auth0/node-jsonwebtoken

 

그럼 이제 본격적으로 JWT를 구현해 보도록 하겠습니다.

로그인과 로그아웃의 UI 및 컨트롤러가 구현된 상태라고 가정하고,

JWT를 발행하고 검증하는 단계에 대해서 정리해 보도록 하겠습니다.

 

먼저 jwt모듈을 require 합니다.

const jwt = require('jsonwebtoken');

 

 

2-2. 토큰 발행하기

토큰을 발행하기 위해서는 아래와 같은 형식을 따르는데요.

payload는 객체나 string형태로 모두 전달 가능하구요.

secret는 signature를 만들 때 사용하는 문자열을 넣어줍니다.

이것을 실수로 클라이언트에 넘겨주면, 바꾸고 전체토큰을 무효화 시켜주어야 겠지요.

jwt.sign(payload, secret, options, [callback])

 

아래와 같이 토큰을 발행 할 수 있습니다.

위에서 본 인자 순서대로 값을 넣어 줍니다.

여기에서 expiresIn는 유효기간인데,

"2 days", "10h", "7d" 같이 시간, 일 등의 단위를 사용할 수 있습니다.

만약 단위를 사용하지 않는다면 ms단위로 처리가 됩니다.

jwt.sign(
  { nickname: 'ladida'}, 
  'secret', 
  { expiresIn: '1h' }
);

 

이렇게 발행된 토큰을 서버에서 HTTP의 Response 헤더에 넣어서 클라이언트에게 전달해 주면 되겠지요.

access token의 경우는 x-access-token (사용자 정의라는 의미에서 붙이는 x를 추가함)과 x-refresh-token과 같은 이름으로 넣어줄 수 있겠습니다.

 

2-3. 토큰 검증하기

토큰 발행하는 것처럼 토큰을 검증하는 로직도 복잡하지 않습니다.

jwt.verify(token, 'wrong-secret', function(err, decoded) {
   if(err) console.log(err);
   console.log("decoded payload", decoded);
});

 

이렇게 해서 토큰을 발행하고 검증하는 것에 대해 알아보았구요.

이러한 토큰을 좀 더 안전하게 사용하는 방법으로서의

액세스 토큰과 리프레쉬 토큰에 대해서 알아보겠습니다.

 

3. 세션관리와 JWT토큰

위에서 세션관리에 사용할 JWT토큰에 대해서 정리해 보았는데요.

세션관리에 대해서 좀 더 보도록 하겠습니다.

 

사용자들은 크롬이나 익스플로러 같은 브라우저를 가지고 접속을 하게 되는데요.
접속후에 로그인이라는 과정을 거쳐 해당사이트의 컨텐츠를 사용하거나 특정 요청을 할 수 있습니다.
그러나 계속 로그인을 하게 하는 것은 매우 불편한 일이므로 보통은 사용자의 세션에 그 상태를 저장하는데요.

 

3-1. 서버에 세션을 저장하는 방법

세션은, 서버의 메모리에 저장하기도 하고, 데이터베이스에 넣을 수도 있습니다.
사용자가 많을수록, 메모리든 데이터베이스든 부하를 받게 되는 부분이 있지만,

언제든 문제가 생기면 무효화 할 수 있으므로 대응이 빠르다고 할 수 있습니다.

 

3-2. 클라이언트에 세션을 저장하는 방법

세션을 클라이언트에 저장할 경우, 암호화된 JWT토큰을 사용해 저장할 수 있는데요.
유저의 로그인정보를 서버에 담지 않을 수 있다는 점에서 부하를 덜 수 있지만,
혹여 탈취되었을 때의 문제가 있으므로 세심한 주의가 필요합니다.

유저가 로그인인증을 하면 서버에서 사인된 토큰을 발급받구요.
클라이언트에서 이 토큰을 저장한 다음,

헤더값에 토큰값을 전송해서 서버에서 검증받는 방식입니다.

 

서버에 상태를 저장하지 않으므로,
서버부하를 상당히 줄여준다는 면에서는 아주 좋습니다.
하지만 반대로 서버가 컨트롤 할 수가 없으므로,
클라이언트의 컴퓨터가 탈취당한 경우 유효시간까지는,
강제로 개별 클라이언트에 해당토큰을 무효화 할 방법이 존재하지 않습니다.

유저가 비밀번호를 변경한 경우에도,
이전 비밀번호로 유효했던 토큰에 대해 서버가 개별적으로 무효화 시킬 수 없으므로,
유효기간이 다 되기까지 계속 유효한 상태가 되버릴 수 있구요.

 

여기에 대한 대안으로, 액세스 토큰과 리프레쉬 토큰을 나누어서 사용하는 방법이 있는데요.

아래에서 보도록 하겠습니다.

 

4. 액세스 토큰과 리프레쉬 토큰

매번 사용자가 로그인 인증을 하게 할 수는 없고, 토큰의 유효기간을 길게 주면,

사용자의 컴퓨터가 탈취당할 경우, 유효기간까지 아이디/패스워드가 빼앗긴거나 다름이 없는 상태가 되는데요.

이에 대한 대응을 하기 위해서 액세스 토큰과 리프레쉬 토큰을 사용할 수 있습니다.

 

방법은 다음과 같은데요.

유효기간이 짧은(예를 들면 1시간 정도) 액세스 토큰과 유효기간이 긴 리프레쉬 토큰을 발행합니다.

액세스 토큰은 아이디/패스워드와 같으므로 많은 일들을 하고 탈취당할 경우 아주 위험해 집니다.

따라서 유효기간을 짧게 해주고, 유효기간이 다 되면,

유저에게 아이디/패스워드를 물어보는 것이 아니고,

유효기간이 긴 리프레쉬 토큰을 이용해서 서버에서 액세스 토큰을 다시 재 발행해서 사용하도록 합니다.

그럼 유저는 굳이 인증을 하지 않으면서도, 서버는 유효성을 계속 검증할 수 있습니다.

 

액세스 토큰의 유효기간이 지나고, 리프레쉬 토큰으로 액세스 토큰을 재 발행받으려고 할 때,

해당 클라이언트가 탈취당한 사실을 서버에서 알고 있을 경우,

해당 id로 액세스 토큰을 발급받지 목하도록 막을 수 있겠지요.

 

이 방법의 단점은, 리프레쉬 토큰을 이용해 액세스 토큰을 발급 받을 때,

매번 서버에 검증을 위해 서버에 접속하므로 부하가 생길 수 있다는 점과,

액세스 토큰의 유효기간동안에는 역시 무방비 상태가 될 수 있다는 점 입니다.

 

728x90

댓글