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