HTTP Stateless Protocol
http 프로토콜은 상태(state)를 유지하지 않는다. 이를 stateless protocol이라 한다.
HTTP 프로토콜은 요청(request)를 전송하고 응답(response)를 전송받은 시점에서 통신이 종료되며 어떠한 상태 정보도 남지 않는다. 즉, 특정 클라이언트에서 동일 서버에 반복하여 접속하여도 각각의 접속은 독립적인 트랜잭션으로 취급된다.
따라서 로그인 화면에서 아이디, 패스워드를 입력하여 사용자 인증 과정을 거친 이후에 재차 웹사이트에 접근하면 로그인 상태임을 인식(유지)할 수 없으므로 매번 사용자 인증 과정을 반복해야 하는 문제가 발생한다.
쿠키와 세션
쿠키는 웹사이트에 접속할 때 생성되는 정보를 담은 임시 파일이다. 쿠키의 데이터 형태는 key와 value형식으로 구성되고, string으로 형태로 되어 있다. 이와 달리 세션은 사용자 정보 파일을 서버에 관리하고 웹서버에 웹 컨테이너의 상태를 유지하기 위한 정보를 저장한다.
여기서 우리는 세션쿠키를 사용할 것인데 이는 웹서버에 저장되는 쿠키를 의미한다. 브라우저를 닫거나 서버에서 세션을 삭제했을 경우 이가 삭제되므로 쿠키보다 보안성 측면에서 보았을 때 매우 좋다. 이 세션 쿠키를 사용하기 위해, express-mysql-session을 아용하여 db에 session 담아두고자 하였다.
세션쿠키
var session = require('express-session')
https://www.npmjs.com/package/express-session/v/1.15.6
npm공식홈페이지에 들어가보면 express-session에 대한 설명이 나와있는데,
버전 1.5.0부터 이 모듈이 작동하기 위해 더 이상 cookie-parser미들웨어 를 사용할 필요가 없습니다. req/res에서 쿠키를 직접 읽고 씁니다. 이제 express-session과 모듈이 동일하여 cookie-parser를 사용하여 cookie-parser를 사용할 경우 문제가 발생할 수 있습니다 .
위와 같은 설명처럼 cookie-parser를 설정해서 사용할 필요가 없다. res.cookie***('쿠키이름', '쿠키값', '옵션객체');***을 설정하여 쿠키를 설정해도 되고, res.setHeader로 하여 쿠키를 설정해도 된다.
app.use(session({
secret: 'session-secret-key',
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true,
secure: false,
},
store: new fileStore()
}));
로 하여 session안에 설정해도 된다.
- dotenv에 있는 설정값을 가져올려고 했는데, 계속적으로 오류가 나서 삽질했다. 그런데 보니 키가 “”로 감싸져 있어서 키로 인식이 안되어서 따로 코드에 작성하였다.
세션의 장점은 Server가 Client에 유일하고 암호화된 아이디(Session ID)를 부여하는 것이라고 생각한다.
데이터는 서버에 보관해 두고 각각의 유저들에대한 고유 id 값을 쿠키에 저장하여 기록한다. 서버는 사용자의 ID값(Cookie에 저장되어 있는)을 비교 및 판단하여 어떤 사용자의 데이터인지와 그 사용자의 접속 여부를 판별할 수 있다.
세션 설정
- httpOnly - 자바스크립트로 쿠키 조회 안되게 한다.
- secure - https 환경에서만 session 정보를 주고 받는다. Node 서버가 프록시 뒤에 있다면 app.use(session({}))을 하기 전에 app.set('trust proxy', 1)을 설정해주는 게 필요하다. 기본값은 false지만 true를 권장한다.
- secret – 쿠키를 임의로 변조하는것을 방지하기 위한 값이며, 이 값을 토대로 세션을 암호화 하여 저장한다.
- resave – 세션에 변경사항이 없어도 항상 저장할 지 설정하는 값이다. 기본값은 true인데, 보통은 false를 많이 쓴다. 계속적으로 db등에 저장되면 부하가 걸린다.
- saveUninitialized – 세션이 최초 만들어지고 수정이 안된다면, 저장되기 전에 uninitialized 상태로 미리 만들어서 저장한다. 보통 false를 많이 쓴다.
- cookie - 세션 ID 쿠키 객체를 설정한다.
- 세션 id 쿠키에 대한 기본값 설정
- { path: '/', httpOnly: true, secure: false, maxAge: null }
세션 저장 방법(Session Store)
이 설정은 기본적으로 브라우저에 저장된다. 세션이 데이터를 저장하는 장소를 Session store라고 한다.
- 서버 메모리(MemoryStore) : 서버에 저장된다. 이는 서버가 중단되면 세션은 모두 초기화 되기 때문에 다른 저장소에 저장할 필요가 있다.
- production 환경에서 MemoryStore의 사용은 적절하지 않으며, 복수 서버 상에서의 Session data 공유도 MemoryStore에서는 불가능하다.
- session-file-store : FileStore에 저장된다. 이는 현재 파일 밖에 sessions이라는 파일이 생성되어 세션이 이곳에 저장된다.
- express-mysql-session : db에 저장되는 방식이다. mysql 데이터베이스에 저장하여 관리가 용이하다.
- Redis : Key-Value 구조의 비정형 데이터를 저장하고 관리하기 위한 오픈소스 기반의 비 관계형 데이터베이스 관리 시스템으로 메모리 기반 DBMS이다. Redis는 공식적으로 Windows를 지원하지 않는다. 다른 루틴으로 하는 방법이 있기에 찾아봐도 될듯하다.
express-mysql-session
내 경우에는 mysql을 사용하여 db에 저장하였는데, sequelize를 사용하여 db를 관리하고 있었다. 그런데 sequelize를 통해서 이 세션을 관리해야 되는 줄 알았는데 그게 아니라 따로 설정을 해서 가져와야 했었다.
- app.js에서 필요한 라이브러리를 임포트한다. 그리고 세션을 담아줄 저장소에 대한 설정을 해준다.
- mysql을 연결하여 로그인이 되면 세션을 저장해준다.
- 여기서 코드가 길어지는 것이 싫다면 options와 sessionStore을 생성하지 않는다. 그리고session을 생성하는 코드에 store부분에 new MySQLStore을 적어 options에 적어놨던 설정을 바로 적는다.
//app.js
require("dotenv").config();
const session = require("express-session");
var MySQLStore = require("express-mysql-session")(session);
var options = {
user:
password:
database:
host:
dialect:
}
var sessionStore = new MySQLStore(options);
app.use(
session({
resave: false,
saveUninitialized: false,
secret: process.env.SESSION_SECRET,
store: sessionStore,
cookie: {
maxAge: 3000 * 60 * 60,
httpOnly: true,
secure: false,
},
})
);
// router.js
const mysql = require("mysql");
const connection = mysql.createConnection({
user:
password:
database:
host:
});
connection.connect();
정보가 유출되면 안되기에 dotenv모듈을 가져와 따로 정보를 저장한다. 그리고 아래 코드도 마찬가지로 mysql에 대한 정보가 유출되면 안되기에 pool로 따로 저장하여 저장해준다. 이에 대한 설명은 따로 글을 작성하여 적어두었다.
계속적으로 오류가 나서 구글링해보았더니 createConnection() 와 connect() 의 중복으로 오류가 발생한 것으로 확인되었다. 이를 주석처리해주니 오류가 없어졌다.
아래와 같은 사이트를 참고하여 작성하였습니다.
https://velog.io/@daeseongkim/Node.js-session-store의-물리적-위치
https://m.blog.naver.com/pjok1122/221555161680
https://poiemaweb.com/nodejs-mysql
https://velog.io/@dev2820/nodejs의-세션
https://velog.io/@hyeinisfree/Node.js-express-Session으로-로그인-구현하기
https://cocoder16.tistory.com/8