What is ⏳ Session

shleecloud·2021년 10월 24일
0

Security

목록 보기
4/6

✍ 들어가며

드디어 Session에 대한 내용이다. 앞선 포스팅에서 Hash, Salt, 대칭키와 비대칭키, HTTPS까지 정리하면서 세션에 필요한 대부분의 선행 지식을 정리했다. 이번 포스팅은 세션의 고유한 특징에 집중해서 작성하려고 한다.

⏳ Session

세션(session)이란 웹 사이트 안의 여러 페이지에 걸쳐 사용되는 사용자 정보(ID)를 저장하는 방법을 의미합니다.

로그인 상태를 유지하기 위한 방법 중 하나다. 인증 정보는 서버에 저장되고 클라이언트는 쿠키에 자신의 세션 ID만 받아서 보안 통신을 유지한다.

그림만으로는 다른 사용자가 세션 ID를 가지고 인증된 행세를 낼 수 있어 위험해 보인다. 하지만 세션은 HTTPS 환경에서 이루어지기 때문에 탈취의 위험에서 안전하다. 쿠키로 Session ID를 주고 받는 시점에선 HTTPS 대칭키가 생성되어 통신하고 있다는 전제로 시작한다.

🥢 대칭키 / 🪡비대칭키 / 📦HTTPS

Session의 특징

  • 보안성이 좋다.
    • 중요한 보안 인증 정보는 서버에서 보유한다.
    • 토큰에 비해 작은 데이터인 세션 ID를 쿠키로 주고 받는다.
    • 따라서 쿠키 보안 설정 httpOnly, secure 옵션을 활성화한다.
    • 서버에서 특정 세션을 막을 수 있다. (기기 강제 로그아웃)
  • 확장성이 나쁘다.
    • 서버가 내려가면 세션 정보가 사라질 수 있다.
    • 이를 보완할 대책으로 세션 클러스터가 있지만 서버 부하가 생긴다.
    • 세션 저장소 DB 부하가 생긴다.

HTTPS -> Session 작업 흐름

클라이언트가 처음 통신을 보내면 서버가 공개키를 보내준다.

클라이언트 웹 브라우저에서 세션키를 만들고 공개키로 암호화해서 서버로 보낸다.

서버는 공개키로 세션키를 확인하고 암호화 통신을 시작한다.
이후 토큰에 세션ID가 있는지 확인한다.

  • 입력받은 ID / Password를 DB에서 확인하고 맞다면 세션ID를 부여한다.
  • 세션 ID를 암호화 후 클라이언트에게 보낸다.
  • 이후 쿠키에 포함된 세션 ID를 확인하고 DB와 통신한다.

💻 Session 구현

express-session 모듈로 세션을 구현한다. 모듈이 대부분의 동작을 처리해줘서 코드상에는 인증서 파일과 설정 파일이 주로 적혀있다.

미들웨어 배치

// TODO: express-session 라이브러리를 이용해 쿠키 설정을 해줄 수 있습니다.
app.use(
  session({
    secret: '@codestates', // 암호화로 쓰이는 키
    resave: false, // 세션을 항상 저장할지 설정
    saveUninitialized: true, // 세션이 저장되기 전 uninitialized 상태로 저장
    cookie: { // 세션 쿠키 설정
      domain: 'localhost', // 쿠키를 보내는 사이트(서버)를 명시
      path: '/', // URL 경로. 하위 경로까지 모두 포함.
      maxAge: 24 * 6 * 60 * 10000, // 쿠키 만료 시간. 초단위.
      // XSRF(cross-site request forgery) 공격 방어 옵션
      sameSite: 'None', // 사이트 외부에서 요청을 보낼 때 쿠키 정책
      // Strict : 외부 도메인 쿠키 차단
      // Lax : 외부 도메인 쿠키 일부 허용(HTTP get method / a href / link href)
      // None : 외부 도메인 쿠키 모두 허용. 강제로 origin 옵션과 같이 써야함
      httpOnly: true, // 클라이언트 스크립트가 쿠키를 못보게 함 (document.cookie)
      secure: true, // HTTPS 환경만 쿠키를 전송
    },
  })
);
// CORS 쿠키 설정 활성화
app.use(
  cors({
    // origin: 'https://localhost:3000',
    origin: true,
    methods: ['GET', 'POST', 'OPTIONS'],
    credentials: true, // 다른 도메인간 자격증명(credential, 쿠키 포함)을 전송할지 여부
  })
);

HTTPS 서버 생성

세션 통신은 HTTPS 환경에서 이루어진다.

if (fs.existsSync('./key.pem') && fs.existsSync('./cert.pem')) {
  server = https
    .createServer(
      {
        key: fs.readFileSync(__dirname + `/` + 'key.pem', 'utf-8'),
        cert: fs.readFileSync(__dirname + `/` + 'cert.pem', 'utf-8'),
      },
      app
    )
    .listen(PORT);
} else {
  server = app.listen(PORT);
}

Session Create

  • Body에 입력된 ID, Password를 DB에서 확인한다.
  • 존재한다면 req.session 객체에 userId키를 만들고 세션 ID를 부여한다
    • 이 과정에서 connect.sid 라는 이름으로 쿠키에 탑재된다.
  • 이후 들어온 통신은 req.session.userId 값을 확인 후 이루어진다.
// 해당 모델의 인스턴스를 models/index.js에서 가져옵니다.
const { Users } = require('../../models');

module.exports = {
  post: async (req, res) => {
    // userInfo는 유저정보가 데이터베이스에 존재하고, 완벽히 일치하는 경우에만 데이터가 존재합니다.
    // 만약 userInfo가 NULL 혹은 빈 객체라면 전달받은 유저정보가 데이터베이스에 존재하는지 확인해 보세요

    const userInfo = await Users.findOne({
      where: { userId: req.body.userId, password: req.body.password },
    });
    // console.log(userInfo);
    // TODO: userInfo 결과 존재 여부에 따라 응답을 구현하세요.
    if (!userInfo) {
      // TODO: 유저 정보가 존재하지 않는 경우
      // your code here
      res.status(400).json({ message: 'not authorized' }).end();
    } else {
      // your code here
      // TODO: 결과가 존재하는 경우 세션 객체에 userId가 저장되어야 합니다.
      // HINT: req.session을 사용하세요.
      req.session.userId = req.body.userId;
      //console.log(req.session);
      // TODO: 유저 정보가 존재하는 경우
      res.status(200).json({ data: userInfo, message: 'ok' }).end();
    }
  },
};

Session Destroy

세션을 파기할 때는 req.session.destroy() 메소드를 사용한다.

    if (!req.session.userId) {
      res.status(400).send({ data: null, message: 'not authorized' });
    } else {
      req.session.destroy();
      res.json({ data: null, message: 'ok' });

참조 URL

https://dev-dain.tistory.com/68
https://tiptopsecurity.com/how-does-https-work-rsa-encryption-explained/
https://cron-tab.github.io/2018/05/31/http-cors-credentials/

profile
블로그 옮겼습니다. https://shlee.cloud

0개의 댓글