오늘은 세션관리와 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])
아래와 같이 토큰을 발행 할 수 있습니다.
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의 장점인 서버에 세션데이터를 넣지 않는다는 전제로)
유저가 비밀번호를 변경한 경우에도,
이전 비밀번호로 유효했던 토큰에 대해 서버가 개별적으로 무효화 시킬 수 없으므로,
유효기간이 다 되기까지 계속 유효한 상태가 됩니다.
위에서 애기한 액세스 토큰과 리프레쉬 토큰을 동시에 발급하는 경우도,
서버에 조회가 많아지는 단점이 있구요.
단점과 장점이 있으므로,
현실 프로젝트에서는 이에 맞게 보완하여 잘 사용할 필요가 있는 것 같습니다.
'NodeJS' 카테고리의 다른 글
Multer이용해서 Firebase의 Storage에 이미지 파일 업로드하기 (0) | 2020.03.30 |
---|---|
Cheerio 사용해서 HTML파싱하여 Scraping하기 (0) | 2020.01.15 |
Jade 또는 Pug 설치하고, 알아두어야 할 문법들 정리 (0) | 2019.02.13 |