gengminy
갱미니의 코딩일지
gengminy
전체 방문자
오늘
어제
  • 분류 전체보기 (61)
    • 🚀 프로젝트 (16)
      • 🎸 고스락 티켓 (4)
      • 🌞 내친소 (5)
      • 🥁 두둥 (7)
    • 📡 백엔드 (31)
      • 🌱 Spring Boot (13)
      • 🐱 Nest.js (10)
      • ⭐ Node.js (8)
    • 🏭 Infra (11)
      • ⚙ 준비를 위한 준비 (2)
      • 🥑 AWS (3)
      • 🐳 Docker (3)
      • ⚡ Github Actions (3)
    • 🌊 프론트엔드 (1)
      • 🌌 React.js (1)
    • 😎 주저리 (2)

블로그 메뉴

  • 💻Github
  • 📸Instagram
  • ✨Blog

공지사항

인기 글

태그

  • 슬랙알림
  • 깃헙액션
  • github
  • oauth2
  • GithubActions
  • SlackAPI
  • docker
  • nest
  • 네스트
  • 스프링부트
  • nestjs
  • AWS
  • JWT
  • 도커
  • OAuth
  • Spring
  • 스프링
  • JSON
  • nodejs
  • springboot

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
gengminy

갱미니의 코딩일지

📡 백엔드/⭐ Node.js

[Nodejs] 쿠키와 세션

2022. 5. 15. 22:02

✅ 쿠키

클라이언트의 정보를 기억하기 위해
서버는 요청에 대한 응답으로 쿠키를 같이 보내고
클라이언트의 웹 브라우저는 다음 요청에
쿠키를 자동으로 같이 보내어
서버가 쿠키를 읽고 클라이언트가 누구인지 파악한다

 

쿠키는 request의 헤더(Cookie)에 담겨 서버에 전송된다
브라우저는 response의 header (Set-Cookie)를 읽어서 저장한다

const http = require('http');
const PORT = 8080;

http.createServer(async (req, res) =>{
    try{
        console.log(req.url, req.headers.cookie);
        res.writeHead(200, {'Set-Cookie' : 'name=gengminy'});
        return res.end('hello my cookie');
    } catch(err){
        console.error(err);
        res.writeHead(404, {'Content-Type' : 'text/html; charset=utf-8'});
        res.end(err.message);    
    }
}
).listen(PORT, ()=>{
    console.log(`server online on port ${PORT}!`);
});

server console
크롬 개발자모드(F12) - Storage - Cookies 에서 확인

새로고침 후 두번째 요청부터 쿠키를 서버가 읽어 콘솔에 출력된다

 

✅ Set-Cookie 옵션

  • {name}={value} : {name}={value}에 해당하는 쿠키를 설정
  • Expires={Date} : {Date}에 해당하는 만료 기간을 설정하여 이 기간이 되면 쿠키 삭제
  • Max-age={second} : 날짜 대신 {second}초 만큼 지나면 쿠키 삭제
  • Domain={Domain} : 쿠키가 전송될 도메인을 {Domain}으로 지정, 기본값은 현재 도메인
  • Path={URL} : 쿠키가 전송될 URL을 지정 가능, 기본 값은 '/'
  • Secure : HTTPS 사용 환경에서만 쿠키 전송 가능
  • HttpOnly : 자바스크립트에서 쿠키에 접근할 수 없도록 지정, 쿠키 조작 방지 위해 사용

 

🔨 예제

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;
}, {});

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();

        // 쿠키 유효 시간을 현재시간 + 5분으로 설정
        expires.setMinutes(expires.getMinutes() + 5);
        res.writeHead(302, {
        Location: '/',
        'Set-Cookie': `name=${encodeURIComponent(name)};
        Expires=${expires.toGMTString()}; HttpOnly; Path=/`,
        });
        res.end();
    } else if (cookies.name) {
        res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' });
        res.end(`${cookies.name}님 안녕하세요`);
    } else {
        try {
        const data = await fs.readFile('./login.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(8080, () => {
    console.log('8080번 포트에서 서버 대기 중입니다!');
});

쿠키가 존재하여 새로고침해도 로그인 정보가 남아있다

하지만 이러한 방식은 쿠키가 노출되어있어 상당히 위험하다

 

 

🔨 세션 예제

사용자 정보가 노출되지 않게 서버측에서 정보를 관리하며

예제에서는 uniqueInt 라는 숫자 값을 대신 보내어

이 값을 통해 서버와 클라이언트가 소통하게 된다

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}님 안녕하세요`);
        console.log(session[cookies.session]);
    } else {
        try {
        const data = await fs.readFile('./login.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(8080, () => {
    console.log('8080번 포트에서 서버 대기 중입니다!');
});

 

server
세션 쿠키

 

 

 

그러나 이와 같은 방법 또한 세션 아이디가 노출되어 있기 때문에 보안상 취약하며

다른 검증된 코드나 모듈을 사용하는 것이 좋다

저작자표시 (새창열림)

'📡 백엔드 > ⭐ Node.js' 카테고리의 다른 글

[Nodejs] Sequelize 로 SQL 데이터베이스 연동하기  (0) 2022.05.21
[Nodejs] Router 객체로 라우팅 파일 분리  (0) 2022.05.17
[Nodejs] 미들웨어의 사용과 자주 쓰이는 미들웨어  (0) 2022.05.16
[Nodejs] express 서버 열기  (0) 2022.05.15
[Nodejs] http 모듈로 간단한 REST API 사용  (0) 2022.05.15
    '📡 백엔드/⭐ Node.js' 카테고리의 다른 글
    • [Nodejs] Router 객체로 라우팅 파일 분리
    • [Nodejs] 미들웨어의 사용과 자주 쓰이는 미들웨어
    • [Nodejs] express 서버 열기
    • [Nodejs] http 모듈로 간단한 REST API 사용
    gengminy
    gengminy
    코딩

    티스토리툴바