김데이의 개발공부

[ TIL ] Day 41 + 해싱솔트, bcrypt 모듈, 유저 기능 세션 / 토큰 본문

코드잇 Node.js(BE) 부트 캠프/TIL (Today I Learn) 📑

[ TIL ] Day 41 + 해싱솔트, bcrypt 모듈, 유저 기능 세션 / 토큰

theday365 2025. 11. 23. 21:02
반응형

🗓️ 수업 일자 : 2025.11.21 (복습 25.11.23)

✨ 오늘의 수업 평가 :  [ REVIEW ]  🌀📝  리마인드 데이 🌀📝

 

수업 시간에 들은 내용에 대해 정확한 구조 파악이 되지 않았는데,

마침 주말이니 조금만 놀고 수업 내용 복습하기!

새로 배운 개념이니 복습, 또 복습!! 🤓

 

📝  오늘 배운 복습 한 내용  

- 해싱 솔트, bcrypt 모듈

- 유저 기능 with Sesstion(세션)

- 유저 기능 with Token(토큰)

 


1. 해싱 솔트, bcrypt 모듈

기초 이론

- Salt(솔트) : 해싱 작업에 사용하는 무작위의 문자열
  Hash(해시) : 솔트(랜덤 문자열)를 받아서 고유한 값으로 변환하는 작업

- 비밀번호 해싱 저장(Salted Hashing, 해싱 솔트)
  : 사용자의 비번에 무작위의 문자열(=해싱)을 조합하여 비밀번호를 안전하게 등록 & 보관

 

Bcrypt 모듈

  • Node.js에서 사용하는 해싱 솔트 모듈
  • Blowfish 암호를 기반으로 설계된 암호화 함수
  • 구현이 쉬우면서도 강력한 해시 메커니즘 중 하나
  • 주요 문법
    1. bcrypt.genSalt(숫자) : Salt를 생성. 숫자는 옵셔널로 기본값은 10이 적용,
                                           숫자가 클수록 해싱 반복횟수가 증가하여 보안이 높아지지만, 속도는 느려짐(연산비용)
    2. bcrypt.hash(User가 입력한 password, 생성한 Salt)
      : User에게 받은 Password와 미리 만들어 둔 Salt를 조합해 해시 생성
    3. bcrypt.compare(User가 입력한 password, DB에 저장된 User의 password)
      : 두 개의 패스워드를 받아, 자동으로 솔트를 추출하여 값 비교함
[user_controller.js]

const express = require('express');
const bcrypt = require('bcrypt');

// A. 회원 가입 
const { username, password } = req.body;

// 1. 솔트(랜덤 문자열)를 생성
const salt = await bcrypt.genSalt(10); 

// 2. 기존 패스워드에 솔트(랜덤 문자열)를 사용해 해싱 작업
const hashedPassword = await bcrypt.hash(password, salt);

// 3. 유저 생성 작업 시 변형한 패스워드를 저장
const user = await prisma.user.create({
  data: { username, password: hashedPassword },
});


===============================================================

//  B. 로그인 
const { username, password } = req.body;

// 1. request body에서 추출 한 user 정보를 사용해 DB에서 저장된 패스워드 가져오기
const userHashedPassword = "..";

// 2. 저장 된 비밀번호와 DB의 비밀번호 검증 (bcrypt가 자동으로 솔트 추출해서 비교)
const isMatch = await bcrypt.compare(password, userHashedPassword);

if (isMatch) {
  res.send('로그인 성공!');
} else {
  res.send('비밀번호 오류');
}

(해당 구문은 솔트 해싱 부분만 작성한 코드 입니다)

 

Bcrypt을 이용한 유저 기능 흐름도 - 회원가입 / 로그인

 

 

+ 추가 

세션, 토큰 복습!! 

- 세션 : 유저가 로그인 하면, "서버"가 유저를 기록 해 두고 현재 사이트를 사용하도록 허용하는 방식. 

            세션 만료 = 유저가 현재 접속한 사이트를 사용 할 시간이 끝났다

- 토큰 : 유저가 로그인 하면, 서버가 유저를 검증 한 뒤 유저 전용키를 "클라이언트"에게 발급 해 주는 방식 

            토큰 만료 = 유저가 특정 작업을 하기 위해 토큰키(=인증키)를 썻지만, 사용 할 수 있는 시간이 끝남

 

 

2. 유저 기능 with Session(세션) 

express-session

  • REST API가 실행될 때 세션을 만드는 express 기능
  • 주요 옵션 정보
    • secret : 세션 보안의 핵심 키, 세션 ID 서명을 만들 때 사용하는 비밀키 정보,
                   해당 값이 노출되면 세션 위조 가능 → 환경변수 .env 파일에 셋팅 한 정보를 불러와 사용. 
    • resave : DB에 저장하는 방식을 설정, boolean값을 사용하는데 거의 false 사용
                    true : 요청이 올 때마다 저장(비효율적) / false : 세션값이 바뀔때만 DB에 저장
    • saveUninitialized : 쿠키 발급 여부를 설정, boolean값을 사용하는데 실무에서는 false를 주로 사용 (연습용 true 괜찮)
                                 true : 모든 작업에 세션 쿠키 발급(빈 세션 쿠키) / false : req.session에 값이 들어가야 세션 쿠키 발급
    • store : 세션을 저장하는 장소, 기본값이 "MemoryStore"로 되어 있어서 지정하지 않으면 세션이 쉽게 휘발됨
                 ⇒ 실무에서는 꼭 저장소를 지정 해야함(Redis 가 많이 사용 됨)
    • cookie : 클라이언트에게 전달 할 "쿠키" 정보를 생성하는 옵션 
      • httpOnly : javascript에서 document.cookie로 정보를 접근하는 것을 방지
      • secure : HTTPS 환경에서만 쿠키 전송
      • sameSite : cookie 정보 제공 범위를 접속 방식을 기준으로 제한
      • maxAge : 발급 된 쿠키의 유효 기간을 설정
[app.js]

import session from 'express-session';

// 전역 선언하여 사용
app.use(
  session({
    secret: SESSION_SECRET,
    resave: false,
    saveUninitialized: false,
    store: new RedisStore({ client: redisClient }),
    cookie: {
      httpOnly: true,
      secure: process.env.NODE_ENV === 'production',
      sameSite: 'lax',
      maxAge: 1000 * 60 * 60 * 24 * 7, // 7 days
    },
  })
);

 

 

세션을 이용한 유저 기능 흐름도 - 로그인 / 글쓰기 / 로그아웃

(Bcrypt 모듈의 기능은 설명에서 생략)

세션을 이용한 유저 기능 흐름도
세션을 이용한 유저 기능 흐름도

 

 

3. 유저 기능 with Token(토큰) 

Cookie-parser

- express는 쿠키를 해석(읽음)하지 못함 ⇒ Token 사용 시 해당 미들웨어를 설치하여 사용 

  (세션에서 express-session이 쿠키 관리까지 해 줬음) 

import cookieParser from 'cookie-parser';
app.use(cookieParser());

 

JWT 메서드

 : JWT(JSON Web Token)을 만들고 검사하는 핵심 메서드 

1.  jwt.sign(payload,secret,options) : 토큰 발급 메서드,
전달 받은 데이터(payload)를 기반으로 데이터를 암호화 하여 토큰 문자열로 만든 뒤 클라이언트에 보내서 인증 시 사용함

2. jwt.verife(token,secret) : 토큰 검증 메서드,

받은 토큰이 정상인지 검사하고, 그 안에 들어있던 payload 등을 꺼낼 수 있음 

// 토큰을 발급할 때 사용하는 비밀 문자열, .env 파일에 작성하는게 원칙
const JWT_SECRET = process.env.JWT_SECRET || "jwt_token_secret_key";

// 토큰 발급
const token = jwt.sign({ userId: 3 }, JWT_SECRET, { expiresIn: '1h' });

// 토큰 검증 
const decoded = jwt.verify(token, JWT_SECRET);

 

Access Token / Refresh Token

- Access Token : 실제 User의 검증 작업에 사용되는 토큰,
                            해커에게 탈취 될 경우 개인 정보가 유출되는 사고가 발생하므로 사용 기한이 짧음.

- Refresh Token : Access Token이 만료 될 경우, 클라이언트가 자동으로 발급 받을 때 사용하는 토큰.
                            Access Token에 대한 간단한 정보밖에 없으며 사용 기한이 긺.

 

토큰을 활용한 유저 기능 흐름도

1. 로그인 / 로그아웃 / 토큰 갱신

(Bcrypt 모듈의 기능은 설명에서 생략)

토큰을 활용한 유저 기능 흐름도 1. 로그인 / 로그아웃 / 토큰 갱신
토큰을 활용한 유저 기능 흐름도 1. 로그인 / 로그아웃 / 토큰 갱신

 

토큰을 활용한 유저 기능 흐름도   

2. 토큰을 활용한 특정 작업

토큰을 활용한 유저 기능 흐름도 2. 토큰을 활용한 특정 작업
토큰을 활용한 유저 기능 흐름도    2. 토큰을 활용한 특정 작업

 

 

 

+ 추가 SQLite 

가벼운 관계형 데이터 베이스로 별도의 DB 셋팅 & 서버를 필요로 하지 않음.

파일 하나가 생성되서 해당 파일 안에 DB가 쌓이는 단순한 형식의 구조

 


 

📃 내일은 뭘 배울까 🤔

- Session / Token / OAuth 심화 기능

반응형