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


1. 세션관리 


사용자들은 크롬이나 익스플로러 같은 브라우저를 가지고 접속을 하게 되는데요.

접속후에 로그인이라는 과정을 거쳐 해당사이트의 컨텐츠를 사용하거나 특정 요청을 할 수 있습니다.

그러나 계속 로그인을 하게 하는 것은 매우 불편한 일이므로 보통은 사용자의 세션에 로그인되었다고 그 상태를 저장합니다.


세션은, 서버의 메모리에 저장하기도 하고, 데이터베이스에 넣을 수 있습니다.

역시나 사용자가 많을수록, 메모리든 데이터베이스든 부하를 받게 됩니다.

물론, 큰 대기업이어서 자체 서버가 남아돈다면 상관없을 수 있겠지만요.


그래서 토큰이라는 것을 사용할 수도 있는데요.

유저의 로그인정보를 서버에 담지 않을 수 있는방법인데요.

아무래도 사이트 개인운영자라면 서버비용이나 부하를 줄일 수 있다는 면에서

이 방법에 관심이 갈 것 같습니다.


토큰을 이용한 방법은 그렇게 복잡하지 않습니다.

유저가 로그인인증을 하면,

서버에서 사인된 토큰을 발급하구요.

클라이언트에서 이 토큰을 저장한다음,

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


그럼 이 토큰을 NodeJS에서는 어떻게 사용할 수 있을지 알아보겠습니다.


2. JSON Web Token(JWT)


뭔가 위에서 말한 스펙을 가지고 있을 것 같은 토큰이름이지요?

맞습니다. 토큰 정보를 가질 수 있고,

토큰이 유효함을 증명할 수 있는 signature또한 가질 수 있습니다.


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

Header는 signing algorithm 과 어떤 타입의 토큰인가로 구성되어 있습니다.


{

  "alg": "HS256",

  "typ": "JWT"

}


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

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


{

  "sub": "77823423",

  "name": "Brown Park",

  "iat": 1516239022

}


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


HMACSHA256(

  base64UrlEncode(header) + "." +

  base64UrlEncode(payload),

  secret)


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




3. JWT 구현


언제나 시작은 npm install 부터인데요.

jsonwebtoken을 설치해 줍니다.


npm install --save jsonwebtoken


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

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


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

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

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


먼저 jwt모듈을 require 합니다.


var jwt = require('jsonwebtoken');


3-1. 토큰 발행하기


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

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

secret는 signature를 만들 때 사용하는 문자열입니다.

이 Secret을 실수로 클라이언트에 넘겨준다면 매우 큰일이므로,

Secret을 바꾸고 전체토큰을 무효화 시켜주어야 합니다.


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


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

여기에서 expiresIn는 유효기간인데,
"2 days", "10h", "7d" 같이 시간, 일 등의 단위를 사용할 수 있습니다.
만약 단위를 사용하지 않는다면 ms단위로 처리가 됩니다.

jwt.sign({

  nickname: 'ladida'

}, 'secret', { expiresIn: '1h' });


이렇게 발행된 토큰은 HTTP헤더에 넣어서 정보를 전달하고 받을 수 있습니다.

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



3-2. 토큰 검증하기


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


jwt.verify(token, 'wrong-secret', function(err, decoded) {

   if(err) console.log(err);

   console.log("decoded payload", decoded);

});


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

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

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


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


뜬금없이 액세스 토큰과 리프레쉬 토큰은 왜 나왔을까요?

좀 더 안전하게 토큰을 발행하고 사용할 수 있도록 하기위한 건데요.

사용자에게 자꾸 인증하게 하기는 힘들고,

그렇다고 무작정 유효기간을 길게 주자니,

만약 사용자의 컴퓨터가 탈취당하거나 한다면,

유효기간까지는 아이디/패스워드가 빼앗긴거나 다름이 없습니다.

이에 대한 대응을 하기 위해서 액세스 토큰과 리프레쉬 토큰이라는 개념을 이용하는 것인데요.


사용방법은 다음과 같습니다.

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

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

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

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

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


만약 사용자의 컴퓨터가 탈취당한경우를 보자면,

이 때 액세스 토큰의 유효기간이 짧으므로 탈취하고 무언가를 하기에 짧은 시간밖에 없습니다.

이 기간동안은 사실상 무방비이긴 합니다.

하지만, 액세스 토큰의 유효기간이 지나고, 리프레쉬 토큰으로 액세스 토큰을 재 발행받으려고 한다면,

해당 클라이언트가 탈취당했다고 서버에서 알고 있다면 더이상 해당 id로 액세스 토큰을 발급받지 목하도록 

막을 수 있기 때문이지요.


5. JWT 단점


세션관리를 하는 데에 있어서 JWT가 서버에 상태를 저장하지 않으므로,

서버부하를 상당히 줄여준다는 면에서는 아주 좋습니다.

하지만 반대로 서버가 컨트롤 할 수가 없으므로,

클라이언트의 컴퓨터가 탈취당한 경우 유효시간까지는,

강제로 개별 클라이언트에 해당토큰을 무효화 할 방법이 존재하지 않습니다.

(JWT의 장점인 서버에 세션데이터를 넣지 않는다는 전제로)


유저가 비밀번호를 변경한 경우에도,

이전 비밀번호로 유효했던 토큰에 대해 서버가 개별적으로 무효화 시킬 수 없으므로,

유효기간이 다 되기까지 계속 유효한 상태가 됩니다.


위에서 애기한 액세스 토큰과 리프레쉬 토큰을 동시에 발급하는 경우도,

서버에 조회가 많아지는 단점이 있구요.


단점과 장점이 있으므로,

현실 프로젝트에서는 이에 맞게 보완하여 잘 사용할 필요가 있는 것 같습니다.

+ Recent posts