로그인 정보를 안전하게 유지하는 방법
사용자 로그인 정보를 안전하게 저장하고, 이를 유지(지속)하기 위한 여러 방안들이 존재한다.
암호화
정보저장
답은 정해져 있지 않다.
그나마 안전한 방법은 사용자의 로그인 정보를 로그인을 하였을 때만 유효하도록 하고, 브라우저를 닫으면 정보를 폐기하는 것이다.
하지만 로그인 정보를 유지하기위해 webstorage, jwt, cookie 등의 기능을 활용하게 되었는데, 이 기능들은 쉽게 공격에 노출될 수 있으므로 신중하게 활용해야 한다.
webstorage
client 측에서 자신의 data를 보관할 수 있는 곳은 localstorage, sessionstorage로 두가지가 존재한다.
localstorage는 영구적으로 data를 저장할 수 있고, 그만큼 쉽게 공격에 노출되어 있을 수 밖에 없다.
sessionstorage는 session id로 구성된 session 정보를 저장하기 위해 존재하는 저장소이며, localstorage와 달리 만료기한이 지나면 정보가 폐기된다.
jwt
jwt는 secrect key(혹은 RSA)를 통해 암호화를 하여 정보를 저장하는 token이다.
header - payload - signature로 구성되어 있고, payload에 사용자 정보가 저장이 된다.
signature 정보를 확인해서 정보가 외부 공격에 노출되었는지 확인할 수 있고, 별도의 옵션(httponly)을 부여하면 데이터 위변조를 확인할 수 있다.
cookie
정해진 만료기한만큼 client 측에 저장되어있는 정보이다.
cookie에 저장되어있는 정보는 장바구니, 즐겨찾는 사이트 등 비교적 보안적으로 중요하지 않은 것들이다.
사용자 정보와 같은 보안적으로 중요한 것들은 웬만해서는 cookie에 넣어선 안된다.
cookie의 보안성이나 저장 등의 단점을 보완하기 위해 webstorage가 고안되었는데, 이 storage마저도 공격에 노출되어 안전한 저장소로 보기엔 무리가 있다.
(※ 차선책은 session(server)에 저장하여 관리하는 것이고, 이는 다른 포스트에서 설명)
cookie를 활용한다는 것에 의미를 둔다.
최종적으로 jwt 정보는 session에 저장하는 것으로 구현할 예정이지만, cookie에 저장하는 방법도 알고있어야 전반적인 인증 logic을 이해할 수 있기 때문에 같이 학습한다.
필요한 module
const express = require('express');
const router = express.Router();
const jwt = require('jsonwebtoken');
router.get('/', (req, res) => {
res.render('jwt.html');
});
jwt token 생성
jwt.sign()을 통해 jwt token을 생성할 수 있으며, 아래 예시는 사용자가 입력한 ID/PW를 jwt token에 저장하는 기본적인 예시이다.
router.post('/add', (req, res) => {
//console.log(req.body);
let {ID, PW} = req.body;
const token = jwt.sign(
{
userID: ID,
userPW: PW
},
'secret',
{
expiresIn: '1h'
}
);
console.log('token is, ' + token);
res.redirect('/jwt');
});
log 확인
token이 잘 생성되었는지 확인한다.
필요한 module
핵심 module은 cookie parser이다.
const express = require('express');
const router = express.Router();
const jwt = require('jsonwebtoken');
const cookieParser = require('cookie-parser');
res.cookie('cookiename', token)
res.cookie를 활용하면 생성한 jwt token을 cookie에 저장할 수 있다.
router.use('/', cookieParser());
router.get('/', (req, res) => {
res.render('jwt.html');
});
router.post('/add', (req, res) => {
//console.log(req.body);
let {ID, PW} = req.body;
const token = jwt.sign(
{
userID: ID,
userPW: PW
},
'secret',
{
expiresIn: '1h'
}
);
console.log('token is, ' + token);
//JWT save to cookie (*cookie-parser)
res.cookie('loginCookie', token, {
});
res.redirect('/jwt');
});
res.cookie('loginCookie', token, {option}')
, 이를 통해 사용자 정보를 저장한 token은 loginCookie라는 이름으로 cookie에 저장된다.router.use('/', cookieParser());
으로 미들웨어 설정을 해주어야, 해당res cookie에 정보가 저장되고 req에서 가져올 수 있다.cookie-parser를 이용하면 req에서 cookie 정보를 가져올 수 있다.
router.post('/check', (req, res) => {
//get login token from cookies
let reqCookie = req.cookies;
let token = reqCookie.loginCookie;
let {ID, PW} = req.body;
//decode
const decoded_data = jwt.verify(
token,
'secret',
//callback 내부의 decoded data는 외부에서 재활용 할 수 없다
//callback은 확인용
/*(err, decoded) => {
console.log(decoded);
}*/
);
if(ID, PW){
if(ID == decoded_data.userID && PW == decoded_data.userPW){
res.send('CORRECT ID / PW');
}else{
res.send('INCORRECT ID OR PW');
}
}
//data 활용용도, 위 callback에서 사용한 이력이 없어야 한다.
//아래에서의 decoded data는 보여지지 않고, 직접 접근해야 한다.
console.log('dedoced data is, ' + decoded_data.userID);
console.log('dedoced data is, ' + decoded_data.userPW);
})
jwt.verify
를 통해 저장한 token 정보를 decode할 수 있고, 이때 반드시 secret-key를 적어주어야 한다.jwt.verify
로 인증한 정보를 callback 함수에서 활용(console 등)할 경우엔 그 이후에 decoded_data를 읽어올 수 없으니 참조하도록 한다.loginCookie라는 이름으로 jwt 정보가 저장되어있고, 이를 활용하면 로그인 정보를 유지하고 인증할 수 있다.
다만 cookie에 httponly 옵션을 추가할 수는 있으나, 민감한 정보가 들어있으면 안되므로 웬만해서는 사용하지 않도록 한다.
cookie 정보는 어디에 저장해야할까?
Cookie 저장 - https://medium.com/sjk5766/jwt-json-web-token-%EC%86%8C%EA%B0%9C-49e211c65b45
localStorage 저장 - https://velog.io/@0307kwon/JWT%EB%8A%94-%EC%96%B4%EB%94%94%EC%97%90-%EC%A0%80%EC%9E%A5%ED%95%B4%EC%95%BC%ED%95%A0%EA%B9%8C-localStorage-vs-cookie
session(server) 저장 -
jwt 생성/발급하기
https://www.youtube.com/watch?v=0D5EEKH97NA
https://medium.com/sjk5766/jwt-json-web-token-%EC%86%8C%EA%B0%9C-49e211c65b45
cookie parser를 활용하여 jwt 정보를 cookie에 저장하기
https://berkbach.com/node-js-%EC%99%80-cookie-session%EC%9C%BC%EB%A1%9C-%EC%82%AC%EC%9A%A9%EC%9E%90%EC%9D%98-%EC%A0%95%EB%B3%B4-%EC%A0%80%EC%9E%A5-part-1-b66d8b35a6e6
jwt 공식 문서
https://jwt.io/