...
세션 동작순서
- 클라이언트 요청 (사용자가 웹사이트 접근)
- 서버는 접근클라이언트의 Request-Header필드인 cookie를 확인하여, 클라이언트가 해당 세션ID를 보냈는지 확인
- 세션ID가 존재하지 않는다면, 서버는 세션ID를 생성해 클라이언트에게 전송.
- 서버에서 클라이언트로 준 세션ID를 쿠키를 사용해 서버에 저장한다.
- 클라이언트는 재접속시, 이 쿠키를 이용하여 세션ID값을 서버에 전달한다.
express-session 모듈
세션 관리용 미들웨어.
로그인 등의 이유로 세션을 구현하거나, 특정 사용자를 위한 데이터를 임시적으로 저장해둘 때 매우 유용하다.
세션은 사용자별로 req.session 객체 안에 유지된다.
app.use(cookieParser(process.env.COOKIE_SECRET);
app.use(session({
secure: ture, // https 환경에서만 session 정보를 주고받도록처리
secret: process.env.COOKIE_SECRET, // 암호화하는 데 쓰일 키
resave: false, // 세션을 언제나 저장할지 설정함
saveUninitialized: true, // 세션에 저장할 내역이 없더라도 처음부터 세션을 생성할지 설정
cookie: { //세션 쿠키 설정 (세션 관리 시 클라이언트에 보내는 쿠키)
httpOnly: true, // 자바스크립트를 통해 세션 쿠키를 사용할 수 없도록 함
Secure: true
},
name: 'session-cookie' // 세션 쿠키명 디폴트값은 connect.sid이지만 다른 이름을 줄수도 있다.
}));
app.get('/', (req, res, next) => {
// 세션에 데이터를 설정하면, 모든 세션이 설정되는게아니라, 요청 받은 고유의 세션 사용자의 값만 설정 된다.
// 즉, 개인의 저장 공간이 생긴 것과 같다.
req.session.id = "hello";
}
express-session은 세션 관리 시 클라이언트에 세션 쿠키를 보낸다.
안전하게 쿠키를 전송하려면 쿠키에 서명을 추가해야하고, 쿠키를 서명할 때 secret의 값이 필요하다.
cookie-parser의 secret과 같게 설정하는 것이 좋다.
session 접근하기
앱에서는 이 세션 객체에 req.session으로 접근이 가능하다.
가령 사용자가 이 페이지에 몇 번이나 들어왔는지 보여주려면 다음과 같은 앱을 구성할 수도 있다.
app.get('/', (req, res, next) => {
if (req.session.num === undefined) // 세션이 없다면
req.session.num = 1; // 세션 등록
else
req.session.num += 1;
res.send(`${req.session.num}번 접속`);
});
같은 세션을 유지하고 있는 한 루트 path로 접속을 할 때마다 req.session.num이 1씩 늘어나게 된다.
이런 식으로 req.session.is_logined를 하면 로그인을 했는지 안 했는지 구현할 수도 있다.
세션 객체를 없애고 싶다면(가령 로그아웃을 해서 세션을 유지할 필요가 없어진다면) req.session.destroy를 하면 된다.
req.session.destroy(err => {
if (err) throw err;
res.redirect(302, '/'); // 웹페이지 강제 이동
});
만약 세션 스토어가 바쁠 때 리다이렉션을 하면 바로 결과가 반영되지 않을 수도 있다.
그럴 때는 req.session.save(err => {})를 하면 된다.
req.session.save를 실행하면 즉시 session 데이터 저장을 하고, err를 매개변수로 갖는 콜백 함수는 save가 모두 끝나면 작업할 내용들을 담고 있다.
if (email === authData.email && pwd === authData.pwd) {
req.session.is_logined = true;
req.session.nickname = authData.nickname;
req.session.save(err => {
if (err) throw err;
res.redirect(302, '/');
});
} else {
res.end("Who?");
}
세션은 서버 메모리(MemoryStore)에 저장된다.
말인즉슨 서버가 한 번 내려가면 모두 초기화돼서 없어진다는 뜻이다.
Session Store
세션 스토어는 세션이 데이터를 저장하는 곳을 말한다.
대표적으로 Memory Store, File Store, Mongo Store 가 있다.
default값은 Memory Store이다. 위에서 말했듯이, 메모리는 서버나 클라이언트를 껐다 키면 사라지는 휘발성이다.
그래서 세션을 저장할 고유 저장소를 따로 지정할 수 가 있는데, 실제 서비스 배포 시에는 데이터베이스를 연결해서 세션을 유지하면 좋다. 보통 Redis를 사용한다고 한다.
뭘 사용할지에 따라서 store를 어떤 걸 설치해야 될지도 다르다.
가령 mySQL에 저장할 거라면 express-mysql-session이 적당해보이고, Redis나 MongoDB에 저장할 거라면 fortune-session이 괜찮아 보인다.
API 문서를 보고 고르면 된다.
가장 흔하게 쓰이는 파일을 이용해, 세션값을 file로 저장해서 관리하는 기능을 구축해보자.
일단 session file store로 설치해 보겠다.
> npm install --save session-file-store
const express = require('express');
const app = express();
const session = require('express-session'); //세션관리용 미들웨어
const fileStore = require('session-file-store')(session); // session file store
app.use(session({
secret: 'secret key', // 암호화
resave: false,
saveUninitialized: true,
cookie: {
httpOnly: true,
},
store: new fileStore() // 세션 객체에 세션스토어를 적용
}));
app.get('/', (req, res, next) => {
console.log(req.session);
if(!req.session.num){ // 해당 세션키가 없다면
req.session.num = 1; // 세션 생성
} else {
req.session.num = req.session.num + 1;
}
res.send(`Number : ${req.session.num}`);
});
app.listen(3000, () => {
console.log('listening 3000port');
});
이렇게 하고 나서 처음 서버를 올리면 sessions 디렉토리가 생긴다.
사용자가 서버에 접속할 때 이 sessions 디렉토리 아래 세션 파일이 생긴다.
세션 쿠키
서명이 붙은 쿠키는 name=name.sign 형태가 된다고 전 강의에서 언급했다.
보통 세션쿠키 이름은 connect.sid로 되어있으며, 언제든지 변경 가능하다.
그리고 value는 인코딩된 값인데 저 문자열을 디코딩 하면,
decodeURIComponent("s%3AGuJZu03OykNcNf6KvCBog5uLjpdsvMQW.GSubUlKEXU0XniHSLXAyuQfrrxnEhfbVA26noc4E7bo");
// 's:GuJZu03OykNcNf6KvCBog5uLjpdsvMQW.GSubUlKEXU0XniHSLXAyuQfrrxnEhfbVA26noc4E7bo'
이런식으로 알수없는 문자열.문자열 식으로 구성된걸 알 수 있다.
저 알수없는 문자열 앞자리와 세션 파일의 파일명과 같은걸 알수 있다.
세션 파일
브라우저의 알파벳 배열에 대응하는 쿠키 값이 파일로 저장된 것을 확인할 수 있다.
또 브라우저를 새로고침 할때 마다 쿠키 값의 num이 1씩 증가한다.
번외
세션도 완벽해보이긴 하지만, 세션을 서버에 저장한다고 치면 동시접속자가 많아질 때 서버에 그만큼 세션이 많이 쌓이게 되므로 과부하가 올 수 있다는 단점이 있다.
또한 세션 하이재킹이라고 세션을 인증하기 위한 세션 id 자체를 빼앗는 세션 가로채기 공격도 있다.
예를 들면 홈페이지 관리자의 세션 아이디를 탈취해서 쿠키값을 관리자의 세션 아이디로 변경하는 안 좋은 상황이 생길 수도 있다.
이 경우에는 세션 id를 뺏으면 ID와 암호를 몰라도 로그인이 가능하기 때문에 위험하다.
이것을 예방하기 위해서는 세션에 로그인했을 때의 IP 값을 저장하고, 페이지를 이동할 때마다 현재 IP와 세션의 IP/브라우저 정보가 같은지 검사하는 방법이 있다고 한다.
# Reference
이 글이 좋으셨다면 구독 & 좋아요
여러분의 구독과 좋아요는
저자에게 큰 힘이 됩니다.