보안

JWT (JSON Web Token)의 사용과 보안 고려 사항

♠디지털 모험일지♠ 2024. 12. 10. 10:45
728x90
반응형
SMALL

JWT (JSON Web Token)의 사용과 보안 고려 사항

JWT는 인증 및 정보를 안전하게 전송하기 위해 사용되는 JSON 기반의 토큰입니다. 클라이언트와 서버 간 인증 및 데이터 교환을 간편하게 처리할 수 있습니다.


1. JWT란?

정의

  • JWT는 클라이언트와 서버 간에 정보를 JSON 형식으로 안전하게 주고받기 위한 토큰입니다.
  • 토큰 자체에 데이터를 포함하고, 서명을 통해 무결성을 보장합니다.

구조

JWT는 세 부분으로 구성되며, .으로 구분됩니다:

  1. Header (헤더): 토큰 타입(JWT)과 암호화 알고리즘 정보를 포함.
  2. Payload (페이로드): 토큰에 담길 데이터(예: 사용자 ID, 권한).
  3. Signature (서명): 토큰의 무결성을 검증하기 위한 암호화된 서명.

JWT 예시:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEyMywiYWRtaW4iOnRydWV9.sflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

2. JWT의 주요 사용 사례

  1. 사용자 인증 (Authentication)
    • 클라이언트가 서버에서 인증을 완료하면, 서버는 JWT를 발급.
    • 이후 요청마다 JWT를 포함해 인증을 대체.
    • 예: 로그인 후 발급된 JWT로 API 호출.
  2. 정보 전달
    • JWT는 클라이언트와 서버 간에 데이터를 전달하는 간편한 방법.
    • 예: 사용자의 역할(Role), 만료 시간(Exp) 등 포함.
  3. API 인증
    • RESTful API와 같은 무상태(State-less) 환경에서 인증에 사용.
    • 각 요청에 JWT를 포함시켜 서버가 상태를 저장하지 않아도 됨.
  4. 싱글 사인온 (SSO)
    • 하나의 로그인으로 여러 시스템에 접근 가능.
    • JWT는 로그인 정보를 공유하는 데 사용.

3. JWT의 보안 고려 사항

3.1. 토큰 보호

  1. 비밀키 관리
    • 서명을 생성할 때 사용하는 비밀키는 절대 노출되어선 안 됨.
    • 안전한 키 저장소 사용.
  2. HTTPS 사용
    • 네트워크에서 데이터가 노출되지 않도록 항상 HTTPS를 통해 전송.
  3. 토큰 저장소 보안
    • 로컬 스토리지 또는 쿠키에 토큰을 저장할 때 보안 설정 필요.
    • 쿠키의 경우 HttpOnly, Secure 플래그 사용.

3.2. 만료 시간 설정

  1. 짧은 만료 시간
    • 토큰의 수명을 짧게 설정하여 유효하지 않은 토큰이 악용되지 않도록 방지.
    • 예: exp 클레임을 설정.
  2. 갱신 메커니즘
    • 만료된 토큰을 새로 발급받을 수 있는 갱신 기능 제공(예: Refresh Token).

3.3. 토큰 내용

  1. 민감 정보 저장 금지
    • JWT는 디코딩이 쉽기 때문에 민감 정보를 포함하면 안 됨.
    • 예: 비밀번호, 카드 정보 등.
  2. 최소한의 데이터만 포함
    • 필요한 정보만 토큰에 담아 크기를 줄이고 보안 리스크 최소화.

3.4. 서명 알고리즘

  1. 안전한 알고리즘 사용
    • HS256 (HMAC SHA-256), RS256 (RSA SHA-256) 등 검증된 알고리즘 사용.
    • none 알고리즘을 절대 사용하지 않음.
  2. 공개키/개인키 관리
    • 비대칭키 알고리즘(RSA 등)을 사용하는 경우 키 관리를 철저히.

3.5. 재생 공격 방지

  1. 토큰 재사용 방지
    • 토큰을 서버에서 블랙리스트에 추가하여 무효화.
    • 예: 중요한 작업 이후 토큰 강제 만료 처리.
  2. Nonce 값 사용
    • 고유 식별자(Nonce)를 추가하여 각 요청의 고유성을 보장.

4. 용어 설명

용어 설명
JWT (JSON Web Token) 클라이언트와 서버 간 데이터를 안전하게 주고받기 위해 사용하는 토큰.
Header (헤더) JWT의 첫 번째 부분으로, 토큰 정보(타입, 암호화 방식)를 포함.
Payload (페이로드) JWT의 두 번째 부분으로, 실제 데이터를 담고 있음. 예: 사용자 ID, 권한 정보.
Signature (서명) JWT의 마지막 부분으로, 헤더와 페이로드의 무결성을 검증하기 위한 암호화된 서명.
HMAC (Hash-based Message Authentication Code) 메시지의 무결성을 보장하기 위해 사용되는 암호화 방법.
Refresh Token JWT 만료 시 새 토큰을 발급받기 위해 사용하는 장기 유효 토큰.
HTTPS 데이터를 암호화하여 안전하게 전송하기 위한 웹 통신 프로토콜.
Nonce (랜덤 값) 각 요청의 고유성을 보장하기 위해 사용되는 임시 랜덤 값.

5. HTML 예제

5.1. JWT 저장과 전송

<!-- HTML: 사용자 로그인 후 JWT 저장 -->
<script>
  // 로그인 요청 후 JWT를 로컬 스토리지에 저장
  const token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...";
  localStorage.setItem("jwt", token);

  // API 호출 시 JWT를 Authorization 헤더에 추가
  fetch("https://api.example.com/protected-data", {
    method: "GET",
    headers: {
      "Authorization": `Bearer ${localStorage.getItem("jwt")}`
    }
  }).then(response => {
    if (response.ok) return response.json();
    throw new Error("Unauthorized");
  }).then(data => {
    console.log("Protected Data:", data);
  }).catch(err => {
    console.error(err.message);
  });
</script>

5.2. 서버에서 JWT 생성과 검증

Node.js 예제 (Express.js):

const jwt = require('jsonwebtoken');

// 비밀키
const SECRET_KEY = "supersecretkey";

// JWT 생성
function generateToken(user) {
  return jwt.sign(
    { id: user.id, role: user.role },
    SECRET_KEY,
    { expiresIn: '1h' } // 1시간 만료
  );
}

// JWT 검증
function verifyToken(req, res, next) {
  const token = req.headers.authorization?.split(' ')[1];
  if (!token) return res.status(401).send("Access Denied");

  try {
    const verified = jwt.verify(token, SECRET_KEY);
    req.user = verified; // 사용자 정보 저장
    next();
  } catch (err) {
    res.status(400).send("Invalid Token");
  }
}

6. 요약

  • JWT 사용: 인증, 정보 전달, API 인증 등에 사용.
  • 보안 고려 사항
    • 민감 정보 포함 금지.
    • HTTPS를 통한 전송.
    • 짧은 만료 시간 설정.
    • 안전한 서명 알고리즘 사용.
  • 실제 구현
    • 클라이언트에서는 토큰을 안전하게 저장 및 전송.
    • 서버에서는 토큰 검증 및 무효화 메커니즘 제공.
반응형
SMALL