Express session 정리

siwoo jang·2024년 10월 7일
0

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들을 사용하는걸 추천.

session 옵션 인자들

  • 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을 사용한다.

session 함수들

  • destroy : session 제거하고 req.session을 unset한다.
  • regenerate : session 재생성. 새 SID와 session 객체가 req.session에 초기화된다.
  • save : session을 store에 저장

사용예시

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 });
  }
});
profile
프론트/백엔드 개발자입니다

0개의 댓글