쿠키는 대충 이해했고.. 세션(session)은?

캡틴 노드랭크·2021년 9월 5일
1

HTTP

목록 보기
9/11

HTTP 프로토콜은 요청을 받고 응답을 보내면 이전 정보는 기억하지 않는다. 그래서 브라우저에 쿠키를 담아 정보를 저장하는 방법을 사용했는데 이 방법으론 보안에 취약한 단점을 가지고있다.

사이트 간 스크립팅(XSS)이란 브라우저에 악성 스크립트를 심어 신뢰하는 웹사이트를 사용하는 사용자들에게 공격하는 방법과 사이트 간 요청을 위조(CSRF)는 사용자가 자신의 의지와는 상관없이 공격자의 의도 행위대로 공격하는 방법같은 보안 취약점이 존재한다.

그래서 상대적으로 안전한 세션(session)을 알아보자.

세션(Session)

세션은 사용자가 웹사이트를 처음 시작부터 종료할 때 까지의 시간 개념을 말한다. 세션 또한 쿠키 를 기반으로 하고 있지만 서버에서 관리한다.

어쨌든 세션도 쿠키를 사용해야하니 세션(session)/쿠키(cookie) 라고도 한다.

세션의 동작 방식

imageRef: hazelcast.com

  • 사용자가 로그인을 한다.

  • 서버는 세션ID를 생성하고, 사용자에게 전송하여, 브라우저의 쿠키에 저장한다.

  • 사용자가 웹페이지의 특정 요청(requset)을 하게되면 세션 ID가 담긴 쿠키를 헤더에 담아 전송한다.

  • 전달받은 서버는 세션 ID를 기반으로 세션에 담긴 정보를 가져온다.

  • 해당 정보로 서버 요청을 처리하여 클라이언트에게 응답한다.

세션 특징

  • 각 클라이언트가 요청을 보내면 고유한 세션ID를 부여한다.

  • 사용자가 처음 접속부터 브라우저를 종료할 때 까지 인증상태를 유지한다.

  • 접속 시간에 제한을 두어 일정시간 응답이 없으면 유지되지 않게 설정할 수 있다.

  • 트래픽이 많을 경우 즉, 사용자가 많아질수록 서버의 메모리를 많이 차지한다.

    • 동접자가 많을수록 서버에 과부하를 주므로 성능 저하의 원인이 된다.
  • 서버에서 관리하기 때문에 쿠키보다 보안면에서 우수하다.

세션은 쿠키의 어느 부분과 다를까?

이렇게 봤을 때는 쿠키를 기반으로 해서 그런지 많이 유사한 모습을 볼 수 있다. 가장 쉽게 구분짓는 방법으론 쿠키는 클라이언트, 세션은 서버에 담는다는 것이다.

그래도 가장 큰 차이점이 존재하는데 다음과 같다.

  • 세션은 서버의 자원을 사용한다.

  • 단, 서버의 자원을 사용하기 때문에 트래픽이 많을 시 퍼포먼스가 떨어진다.

  • 쿠키처럼 세션도 만료시간을 정할 수 있으며, 브라우저가 종료되면 만료시간 상관없이 삭제된다.

  • 쿠키는 요청(request)에서 탈취당할 우려가 있지만, 세션은 쿠키에 세션ID만 저장하고 서버에서 처리하기 때문에 보안상 더 우수하다.

  • 쿠키의 경우.. 로그인을 안해도 장바구니에 물건을 담아둔 정보, 자동 로그인 및 팝업창 "하루 보이지 않기" 등 민감하지 않는 정보를 담아둔다.

  • 세션의 경우 민감한 개인정보를 담아두며, 서버 퍼포먼스 상 이득을 챙기기 위하여 세션 관리 서버를 따로 만들어 관리한다고 알고있다.

세션 사용방법

본인은 node.js,express ...,passport .... 등등 라이브러리를 사용하고 있으며, Sequelize라는 ORM(Object-Relational Mapping) 라이브러리를 사용하고 있다.

기본 expresssession라이브러리를 활용하여 구현하는 법과 passport 를 활용해 구현하는 법을 알아보자.

기본구현 시

express-session이 필요한 패키지이다. 그러나 해당 패키지만으론 저장소를 구현할 수가 없다.. 이점이 가장 아쉬운데 공식 라이브러리 npm페이지에선 친절히 알려주고 있다.

두 방법으로 저장하는데, MYSQL sessionredis 스토리지를 활용한다. 취향껏 결정하자.

npm i redis connect-redis express-session --save

하지만 나는 MYSQL을 활용할 것이므로, 아래의 명령어를 통해 패키지를 설치한다.

npm i express-mysql-session express-session --save

const mysql2 = require("mysql2/promise")
const session = require("express-session");
const MySQLStore = require("express-mysql-session")(session);

const options = {
	host: 'localhost',
	port: 3306,
	user: 'your db username',
	password: 'your db password',
	database: 'your db name'
}

const connection = mysql2.createPool(options);
const sessionStore = new MySQLStore({}, connection);

app.use(session({
    key: "session_cookie_name",
    secret: "session_cookie_secret",
    store: sessionStore,
    resave: false,
    saveUninitialized: false,
})
        
        ....

MySQL2 사용하므로 const mysql2 = require("mysql2/promise")이렇게 불러와주었다.

로그인은 cookie 대신 session으로 할경우는 다음과 같다.

router.post('/login', async (req,res) => {
const {email, password} = req.body
const users = await User.findOne({ where: { email } });
const bcryptPwd = await bcrypt.compareSync(password, users.password)

if(email === users.email && password === bcryptPwd){
  
  req.session.user = {
    uid = users.id
    email = users.email;
  }
    res
      .send("login success");  
      .redirect('/');
  } else {
    res
      .send('Invalid email or password')
      .redirect('/');
  }
}

로그아웃은 세션을 날려버리면된다.

router.get('/logout',(req,res) => {
    req.session.destroy();
    res.redirect('/');
});

아니면 하나만 날리는 방법으로

router.get('/logout',(req,res) => {
    delete req.session.user
    req.session.save(() => {
      res.redirect('/');
    }
});

이렇게 해주면된다.

profile
다시 처음부터 천천히... 급할필요가 없다.

0개의 댓글