노드

노드 세션 사용하기

포칼이 2023. 4. 13. 16:36

쿠키의 정보는 노출되고 수정되는 위험이 있다. 해결방법은 다음과 같다

  • 중요한 정보는 서버에서 관리하고 클라이언트에는 세션 키만 제공
  • 서버에 세션 객체(session) 생성 후, uniqueInt(키)를 만들어 속성명으로 사용
  • 속성 값에 정보를 저장하고 uniqueInt를 클라이언트에 보냄
//session.js
const http = require('http');
const fs = require('fs').promises;
const url = require('url');
const qs = require('querystring');

const parseCookies = (cookie = '') =>
  cookie
    .split(';')
    .map(v => v.split('='))
    .reduce((acc, [k, v]) => {
      acc[k.trim()] = decodeURIComponent(v);
      return acc;
    }, {});

const session = {};

http.createServer(async (req, res) => {
  const cookies = parseCookies(req.headers.cookie);
  if (req.url.startsWith('/login')) {
    const { query } = url.parse(req.url);
    const { name } = qs.parse(query);
    const expires = new Date();
    expires.setMinutes(expires.getMinutes() + 5);
    const uniqueInt = Date.now();
    session[uniqueInt] = {
      name,
      expires,
    };
    res.writeHead(302, {
      Location: '/',
      'Set-Cookie': `session=${uniqueInt}; Expires=${expires.toGMTString()}; HttpOnly; Path=/`,
    });
    res.end();
  // 세션쿠키가 존재하고, 만료 기간이 지나지 않았다면
  } else if (cookies.session && session[cookies.session].expires > new Date()) {
    res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
    res.end(`${session[cookies.session].name}님 안녕하세요`);
  } else {
    try {
      const data = await fs.readFile('./cookie2.html');
      res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
      res.end(data);
    } catch (err) {
      res.writeHead(500, { 'Content-Type': 'text/plain; charset=utf-8' });
      res.end(err.message);
    }
  }
})
  .listen(8085, () => {
    console.log('8085번 포트에서 서버 대기 중입니다!');
  });

서버 쪽에서 데이터를 저장할 seeson 객체를 만들었다. 그리고 쿠키 포스팅했을 때와 다 같은데 

const uniqueInt = Date.now(); 이 부분부터 달라진다. 

uniqueInt라는 키를 만들었고 현재 시간을 거기에 할당했다. 

다음에 만든 session 객체에 uniqueInt 를 키로하는 값 name, expires를 할당했다.  

이때 브라우저에는 name이나 expires를 보내는게 아니라 uniqueInt를 보낸다. 고유한 키 값만 보내는 것이다. 

쿠키와는 다르게 쿠키의 값이 168137...로 표시가 되는 것을 볼 수 있다. 따라서해커들이 봤을때 어떤 값을 쓰고 있는지 모를 가능성이 높다. (보안성이 훨씬 좋다)

 

그리고 세션 쿠키가 존재하고, 만료 기간이 지나지 않았다면 다음번 호출때는

else if (cookies.session && session[cookies.session].expires > new Date()) {
    res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
    res.end(`${session[cookies.session].name}님 안녕하세요`);

이 부분이 실행된다. 

 

마지막에 session 에서 이름만 꺼내서 사용하는 것을 볼 수 있다. 

즉, 브라우저는 서버로 세션 쿠키만 보내주고 서버쪽에서는 세션에 접근해서 이름을 꺼내와서 쓰는 것이다. 

브라우저는 의미를 알 수 없는 키를 가지고 있는 것이고 그 키를 통해서 서버의 실제로 중요한 데이터에 접근을 하게 된다.

 

*이해를 돕기 위해 세션을 직접 구현했지만 실 서버에서는 세션을 직접 구현하는건 지양하자.