백엔드/Node.js

JSON Web Token

Ryuzy 2025. 4. 26. 22:52
728x90
반응형

1. JSON Web Token(JWT)

JSON Web Token(JWT)은 서버와 클라이언트 사이에서 인증 정보를 안전하게 전달하기 위한 컴팩트하고 독립적인 토큰입니다. JWT는 세 부분(헤더, 페이로드, 서명)으로 구성되어 있으며, 페이로드에는 사용자 정보나 인증 관련 데이터가 담기고, 서명은 토큰의 무결성을 검증하는 데 사용됩니다. 주로 로그인 이후 발급되어 클라이언트가 저장하고 있다가 서버 요청 시 함께 전송하며, 서버는 토큰만 검증하고 별도로 세션을 저장하지 않아 상태를 유지하지 않는(stateless) 인증 방식을 구현할 수 있습니다. 이로 인해 모바일 앱, SPA(싱글 페이지 어플리케이션), 마이크로서비스 API 서버에서 널리 사용됩니다.

npm install jsonwebtoken

 

JWT는 크게 3부분으로 나눠져 있습니다

1. Header (헤더)

토큰이 어떤 알고리즘으로 암호화되었는지, 어떤 형식인지를 알려주는 부분입니다.

{
  "alg": "HS256", // 서명 알고리즘 (예: HMAC SHA-256)
  "typ": "JWT"    // 토큰 타입 (JWT 고정)
}

 

  • 보통 alg에는 HS256, RS256 같은 서명 알고리즘이 들어갑니다.
  • typ는 거의 항상 "JWT"로 설정됩니다.
  • 이 헤더는 JSON 객체를 Base64Url 인코딩해서 토큰의 첫 번째 부분이 됩니다.

 

2. Payload (페이로드)

실제 데이터(사용자 정보, 권한 등)가 담기는 부분입니다.

{
  "userid": "apple",
  "role": "user",
  "iat": 1697682149,
  "exp": 1697685749
}

 

 

userid 사용자 고유 ID
role 사용자 권한(예: user, admin)
iat 토큰 발급 시간 (issued at, 초 단위)
exp 토큰 만료 시간 (expiration, 초 단위)

 

  • 여기에 들어가는 데이터는 누구나 볼 수 있습니다! (암호화 X)
  • 민감한 정보(비밀번호, 카드번호)는 절대 담으면 안 됩니다!
  • 이것도 JSON을 Base64Url 인코딩해서 토큰의 두 번째 부분이 됩니다.

 

3. Signature (서명)

 

헤더와 페이로드가 변조되지 않았는지 검증하는 부분입니다.

HMACSHA256(
  Base64UrlEncode(header) + "." + Base64UrlEncode(payload),
  secret
)

 

  • 인코딩된 Header + . + 인코딩된 Payload를 하나의 문자열로 합칩니다.
  • 서버만 알고 있는 비밀키(secret key)를 사용해서 서명합니다.
  • 서버는 서명을 검증해서 토큰이 위조되지 않았음을 확인할 수 있습니다.
  • 비밀키를 아는 서버만 서명을 검증할 수 있습니다.
import jwt from "jsonwebtoken";

const secretKey = "!@#$%^&*()"; // 서버 비밀키 (절대 공개 X)

// 1. 토큰 생성
const token = jwt.sign(
  { userid: "apple", role: "admin" }, // payload (토큰에 담을 데이터)
  secretKey, // 비밀키
  { expiresIn: "1h" } // 옵션: 1시간 뒤 만료
);

console.log("생성된 토큰:", token);

// 2. 토큰 검증
try {
  const decoded = jwt.verify(token, secretKey);
  console.log("검증된 토큰 내용:", decoded);
} catch (error) {
  console.error("토큰 검증 실패:", error.message);
}

 

 

 

2. bcrypt

bcrypt는 비밀번호와 같은 민감한 데이터를 안전하게 저장하기 위해 사용하는 해시 알고리즘입니다. 일반적인 암호화와 다르게, bcrypt는 입력된 값을 복호화할 수 없고, 오직 비교만 가능하게 설계되어 있어 비밀번호 유출 위험을 크게 줄여줍니다. 특히 bcrypt는 단순 해시가 아니라 Salt(솔트, 무작위 문자열)를 추가하고, 복잡한 연산을 반복(iteration)하여 해커가 무차별 대입 공격(브루트포스 공격)을 시도할 때 걸리는 시간을 늘려줍니다. 이 덕분에 bcrypt는 웹 애플리케이션에서 비밀번호 저장에 있어 가장 널리 사용되는 안전한 방식으로 평가받고 있습니다.

npm install bcrypt
Salt 해시하기 전에 추가하는 무작위 문자열
Hash Salt를 포함해서 만든 결과값
Rounds 해시 연산을 몇 번 반복할지 정하는 숫자 (예: 10번 반복)

 

import bcrypt from "bcrypt";

const password = "apple1004"; // 사용자가 입력한 비밀번호
const saltRounds = 10; // 연산 반복 횟수 (10~12 추천)

// 1. 비밀번호 해시화 (저장할 때)
async function hashPassword(password) {
  const hashed = await bcrypt.hash(password, saltRounds);
  console.log("해시된 비밀번호:", hashed);
  return hashed;
}

// 2. 비밀번호 검증 (로그인할 때)
async function verifyPassword(inputPassword, hashedPassword) {
  const isMatch = await bcrypt.compare(inputPassword, hashedPassword);
  console.log("비밀번호 일치 여부:", isMatch);
  return isMatch;
}

// 사용 예시
async function runExample() {
  const hashed = await hashPassword(password); // 비밀번호 암호화

  await verifyPassword("apple1004", hashed); // 비밀번호 맞음 → true
  await verifyPassword("apple8282", hashed); // 비밀번호 틀림 → false
}

runExample();

 

 

 

728x90
반응형

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

라우트  (0) 2025.04.23
Express  (0) 2025.04.22
EJS  (0) 2025.04.22
http 모듈  (0) 2025.04.22
파일 입출력  (0) 2025.04.22