
Session은 서버단에서 처리되고, 브라우저의 cookie에 Session ID 만 전달한다.
Session ID만 쿠키로 전달하면 되므로 데이터는 서버에서 안전하게 처리된다.
사용법은 다음과 같이 사용하면 된다.
const express = require('express');
const cors = require('cors');
const session = require('express-session');
const config = require('./config/config');
const loginService = require('./services/loginService');
const app = express();
app.use(cors({
origin: 'http://localhost:3000',
credentials: true
}));
app.use(express.json());
// Session 설정
app.use(session({
secret: config.SESSION_SECRET,
resave: false,
saveUninitialized: false,
cookie: {
httpOnly: true, // 클라이언트 스크립트가 쿠키에 접근하지 못하도록 설정
secure: false, // https가 아닌 환경에서도 사용 가능하도록 설정
sameSite: 'lax', // CSRF 공격으로부터 보호하기 위한 설정
domain:'localhost', // 쿠키가 전송될 수 있는 도메인을 설정해야함. 로컬개발환경에서는 localhost
// secure 설정시 https 서버 설정이 필요.
// 만약 https 설정이 아닌경우, 쿠키가 set 되지 않는다
/* 크롬 80버전부터 CSRF공격으로 부터의 보안강화를 위해 sameSite 기본 속성값이 'none'에서 'lax'로 변경된다
CORS REQUEST 보내려면 sameSite:'lax'로 하거나 sameSite:'none'으로 해야지 된다.
*/
maxAge: 24 * 60 * 60 * 1000 // session 유효기간 24 hours
}
}));
// session 검증 미들웨어
const authenticateSession = (req, res, next) => {
if (req.session.userId) {
next();
} else {
return res.status(401).json({ message: 'Unauthorized' });
}
};
default servier-side session 저장소는 MemoryStore다.
이는 production 환경으로 설계된게 아니라 디버깅,개발단계에서 사용하려고 한거다.
redis 등 다른 store들을 사용하는걸 추천.
secret : 필수값. 32바이트의 엔트로피를 가지는걸 권장.
resave : session을 store에 다시 강제로 저장시키는지 여부.
saveUninitialized : uninitialized session을 store에 강제저장할지 여부
httpOnly : true일 경우 클라이언트 스크립트를 허용하지않음. XSS Attack 방지
secure : true 일 경우 HTTPS에서만 쿠키가 SET 되게 함. 만약 Node 서버가 프록시를 쓰고 있다면 "trust proxy"를 사용해야함.
sameSite : 'lax' : 느슨한 동일 사이트 정책 적용.'none' : 명시적인 cross site cookie 사용.
크롬 80버전부터 CSRF공격으로 부터의 보안강화를 위해 sameSite 기본 속성값이 'none'에서 'lax'로 변경된다. CORS REQUEST 보내려면 sameSite:'lax'로 하거나 sameSite:'none'으로 해야지 된다.
domain : 허용할 도메인 주소
maxAge : 유효시간. expire랑 같이 쓰면 안됨.
path : 쿠키가 저장될 경로. default는 '/'
genid : new session id 생성
name : session ID 쿠키의 이름. default는 connect.sid
proxy : 노드서버가 프록시 뒤에 있다면 설정해줘야함. secure cookie를 set할때 X-Forwarded-Proto 헤더를 통한 역방향 proxy를 신뢰할지 여부를 결정. default 값은 undefined
역방향 proxy는 인터넷에서 웹 서버에 대한 액세스를 제공하는 데 사용된다
X-Forwarded-Proto (XFP) 헤더는 클라이언트가 당신의 프록시 또는 로드 밸런서에 접속하는데에 사용했던 프로토콜(HTTP 또는 HTTPS)이 무엇인지 확인하는 사실상의 표준 헤더이다.
true는 X-Forwarded-Proto 헤더가 사용되고,
false 일 때 모든 헤더는 무시되고, 연결은 secure only 로 처리된다.
undefined는 express의 "trust proxy" setting을 사용한다.
사용예시
app.post('/login', async (req, res) => {
try {
const { username, password} = req.body;
const userIp = req.ip;
const result = await loginService.login(username, password, userIp);
if (result.user) {
// 로그인 시 세션 재생성
req.session.regenerate(() => {
// 로그인 성공 시 세션에 userId, username 저장
req.session.userId = result.user.userId;
req.session.username = result.user.username;
req.session.save(() => {
return res.json({ message: '로그인 성공', user: result.user });
});
});
} else {
return res.status(401).json({ message: 'Invalid credentials' });
}
} catch (error) {
console.error('Login error:', error);
return res.status(400).json({ message: error.message });
}
});
app.post('/logout', async (req, res) => {
try{
const userIp = req.ip;
const username = req.session.username;
const result = await loginService.logout(username, userIp);
req.session.destroy((err) => {
if (err) {
return res.status(500).json({ message: 'Could not log out, please try again' });
}});
return res.json(result);
} catch (error) {
return res.status(400).json({ message: error.message });
}
});