JSON Web Token

현서·2025년 4월 28일

백엔드

목록 보기
7/18
post-thumbnail

1. JSON Web Token(JWT)

"서버와 클라이언트 간에 데이터를 안전하게 주고받기 위한 토큰(Token)"

  • 토큰 자체에 사용자 정보가 담겨 있어서 서버가 별도로 세션을 저장할 필요 없이 토큰만 검증하면 사용자를 식별할 수 있다.
  • 주로 인증(Authentication) 또는 정보 교환(Information Exchange) 에 사용한다.

➿JWT 구조
JWT는 3개의 부분으로 나뉘어 있다:

1. Header
타입(typ)과 해시 알고리즘(alg) 정보가 들어있다.

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

2. Payload
실제 담고 싶은 사용자 정보(Claim)가 들어간다.

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

3. Signature
비밀 키(secret)를 이용해서 Header와 Payload를 암호화한 값이다.

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

➿ JWT 사용 흐름

  1. 사용자가 로그인하면 서버가 JWT를 발급한다.

  2. 클라이언트(브라우저, 앱)는 이 토큰을 저장한다. (보통 localStorage나 cookie에)

  3. 클라이언트가 서버에 API 요청할 때마다 토큰을 같이 보낸다. (주로 Authorization: Bearer 헤더로)

  4. 서버는 토큰을 검증해서 요청을 허용하거나 거부한다.

✅ JWT 장점

  1. 서버가 사용자 정보를 따로 저장할 필요 없음 (stateless)
  2. 빠른 인증 처리
  3. 다양한 서버 간에 인증 정보 공유 가능 (예: 마이크로서비스)

⚠️ JWT 주의점

  1. Payload는 암호화되지 않음
    → 누구나 내용을 볼 수 있으니 민감한 정보(비밀번호 등)는 넣으면 안됨.
  2. 토큰 탈취에 주의
    → HTTPS 사용 필수, 보안적으로 주의해야 함.
  3. 토큰 무효화 어려움
    → 한번 발급된 토큰은 만료시간이 끝나기 전까지 유효.
    (강제 만료하려면 별도 관리 필요)

설치

npm install jsonwebtoken
import jwt from "jsonwebtoken";

const secretKey = "!@#$%^&*()";

// 1. 토큰 생성
const token = jwt.sign({ userid: "apple", role: "admin" }, secretKey, {
  expiresIn: "1h",
});

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

// 2. 토큰 검증
try {
  const decoded = jwt.verify(token, secretKey);
  console.log("검증된 토큰 내용: ", decoded);
} catch (error) {
  console.log("토큰 검증 실패: ", error.message);
}
C:\Hsgo\Nodejs>node 18_JWT.mjs
생성된 토큰:  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyaWQiOiJhcHBsZSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTc0NTgwMDU5MywiZXhwIjoxNzQ1ODA0MTkzfQ.1Rz6iyzQD_C7VD3-CsC01iHVb7Hva1KFmXlQPbHWmQ4
검증된 토큰 내용:  { userid: 'apple', role: 'admin', iat: 1745800593, exp: 1745804193 }

밑에는 실패했을 때!

C:\Hsgo\Nodejs>node 18_JWT.mjs
생성된 토큰:  eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyaWQiOiJhcHBsZSIsInJvbGUiOiJhZG1pbiIsImlhdCI6MTc0NTgwMDU4MCwiZXhwIjoxNzQ1ODA0MTgwfQ.5Z6k7farDkAy8a8ENCZi9roz0_KXn7hg-Hzv4Qaf2pI
6k7farDkAy8a8ENCZi9roz0_KXn7hg-Hzv4Qaf2pI
토큰 검증 실패:  tokeb is not defined
개념의미
Encode (인코딩)데이터를 다른 형식으로 변환해서 전송하거나 저장할 수 있도록 바꾸는 것
Decode (디코딩)인코딩된 데이터를 다시 원래 형태로 복원하는 것

2. bcrypt

비밀번호 같은 민감한 데이터를 안전하게 암호화(해시) 하기 위해 사용하는 알고리즘이다.

➿ bcrypt를 쓰는 이유

  • 비밀번호를 평문(plain text) 으로 저장하면, 데이터베이스가 해킹당했을 때 큰 사고로 이어질 수 있다.

  • bcrypt는 단방향 해시 함수라 복호화(원래 비밀번호 복원)가 불가능하다.

  • 추가로 salt(솔트) 라는 랜덤 데이터를 붙여서 해시하기 때문에, 같은 비밀번호라도 해시 결과가 다르게 나온다.

✅ 비밀번호를 비교할 때는 "비밀번호를 다시 해시해서 결과를 비교" 한다.

  • Salt: 해시를 더 안전하게 만드는 랜덤 값
  • Hashing: 비밀번호를 변환하는 작업 (복원 불가)
  • Cost Factor(=Rounds): 해시 계산을 얼마나 반복할지 정하는 값 (보통 10~12 사용)

설치

npm install bcrypt
import bcrypt from "bcrypt";

const password = "apple1004";
const saltRounds = 10;

// 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);
  await verifyPassword("apple8282", hashed);
}

runExample();
C:\Hsgo\Nodejs>node 19_bcrypt.mjs 
해시된 비밀번호 :  $2b$10$wACiuhcCxDSEijykNwHAkObMRYI2UWw8dHjAlBcy3rX6iT/j/kQo.
비밀번호 일치 여부:  true
비밀번호 일치 여부:  false
profile
The light shines in the darkness.

0개의 댓글