JWT

김뉴오·2025년 4월 22일

키워드

목록 보기
1/15
post-thumbnail

JWT 로그인

JWT(JSON Web Token)는 로그인 및 인증 시스템에서 널리 사용되는 토큰 기반 인증 방식이다. 로그인 후 서버가 클라이언트에게 JWT를 발급하며, 이후 클라이언트는 해당 JWT를 사용하여 인증된 요청을 서버에 보낸다.


JWT 구조

JWT는 크게 Header, Payload, Signature 세 부분으로 구성된다.

plaintext
복사편집
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
.
eyJ1c2VyX2lkIjoxMjMsIm5hbWUiOiJKb2huIERvZSJ9
.
SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
  1. Header (헤더)
    • 어떤 알고리즘을 사용할지 정의 (예: HS256)
  2. Payload (페이로드)
    • 유저 정보(예: user_id, role 등)를 포함
  3. Signature (서명)
    • 토큰의 무결성을 보장하기 위한 서명

JWT 기반 로그인 흐름

  1. 사용자가 로그인 요청을 보냄

    • 아이디와 비밀번호를 서버로 전송
  2. 서버가 사용자의 아이디/비밀번호를 확인

    • 데이터베이스에서 해당 사용자가 존재하는지 검증
  3. JWT를 생성하여 클라이언트에게 반환

    • JWT에는 사용자 정보를 포함할 수 있으며, 서버의 SECRET_KEY로 서명되어 위변조가 불가능함
  4. 클라이언트가 JWT를 쿠키에 저장

  • 이후 클라이언트는 요청을 보낼 때 쿠키를 자동으로 포함하여 서버로 전송
  1. 서버가 쿠키에서 JWT를 확인하고 인증 처리
  • 서버는 JWT의 서명을 검증하여 정상적인 토큰인지 확인
  • 유효하면 요청을 처리하고, 그렇지 않으면 401(Unauthorized) 응답

JWT를 쿠키에 저장하는 이유

JWT를 저장하는 방법에는 여러 가지가 있지만, 쿠키(cookie) 를 사용하는 것이 보안적으로 유리하다.

쿠키를 사용하는 이유

자동 전송

  • HTTP 요청마다 브라우저가 자동으로 쿠키를 포함시켜 주기 때문에 클라이언트에서 별도로 JWT를 관리할 필요가 없음

보안 강화 (HttpOnly, Secure 옵션 사용 가능)

  • HttpOnly: JavaScript에서 쿠키에 접근할 수 없도록 막음 (XSS 공격 방어)
  • Secure: HTTPS에서만 쿠키를 전송하도록 제한하여 중간자 공격(Man-in-the-Middle Attack)을 방지

CSRF 방지

  • 쿠키에는 SameSite 옵션을 설정하여 CSRF(사이트 간 요청 위조) 공격을 예방할 수 있음

브라우저 세션 유지 가능

  • 쿠키 만료 시간을 설정하면 브라우저를 닫아도 유지할 수 있음

쿠키를 사용할 때 고려해야 할 점

XSS(크로스 사이트 스크립팅) 공격 방지

  • HttpOnly=True 옵션을 설정하면 JavaScript에서 쿠키 접근이 불가능하여 공격자가 토큰을 탈취하는 것을 방지할 수 있음

CSRF(사이트 간 요청 위조) 공격 방지

  • SameSite="Lax" 또는 "Strict" 설정을 하면 CSRF 공격을 차단할 수 있음
  • SameSite="Strict"은 가장 보안이 강하지만, 다른 사이트에서 쿠키를 전송하지 않기 때문에 일부 기능(소셜 로그인 등)이 제한될 수 있음
  • SameSite="Lax"는 보안과 편의성의 균형을 맞춘 설정

JWT의 만료 시간 고려

  • JWT는 기본적으로 한 번 발급되면 만료 시간이 지나기 전까지 유효하기 때문에, 만료 시간이 지나면 새로 로그인해야 함
  • Refresh Token을 사용하면, Access Token이 만료되었을 때 새로 발급받을 수 있음

로그아웃 처리

  • JWT는 서버에서 삭제할 수 없기 때문에, 로그아웃 시 클라이언트에서 쿠키를 삭제하는 방식으로 처리해야 함

JWT와 쿠키의 조합 – 보안 강화를 위한 추가 옵션

  • HttpOnly → XSS 공격 방지 (JavaScript에서 접근 불가능)
  • Secure → HTTPS에서만 쿠키 전송 가능
  • SameSite="Lax" 또는 "Strict" → CSRF 방지
  • 쿠키 만료 시간 설정 → 세션 유지 또는 자동 로그아웃 가능

이렇게 설정하면 보안성이 높은 JWT 기반 로그인 시스템을 구축할 수 있다!



Flask에서 JWT + 쿠키 구현 예제

python
복사편집
from flask import Flask, request, jsonify, make_response
import jwt
import datetime

app = Flask(__name__)
SECRET_KEY = "mysecretkey"  # JWT 서명에 사용할 키

# 로그인 API (JWT 생성 및 쿠키 저장)
@app.route('/login', methods=['POST'])
def login():
    data = request.json  # 사용자 입력 데이터
    username = data.get("username")
    password = data.get("password")

    if username == "admin" and password == "password":  # 예제용 인증
        token = jwt.encode(
            {"user": username, "exp": datetime.datetime.utcnow() + datetime.timedelta(hours=1)},
            SECRET_KEY, algorithm="HS256"
        )

        response = make_response(jsonify({"message": "로그인 성공"}))
        response.set_cookie("token", token, httponly=True, secure=True)  # JWT를 쿠키에 저장
        return response

    return jsonify({"message": "로그인 실패"}), 401

# 인증 확인 API (쿠키에서 JWT 확인)
@app.route('/protected', methods=['GET'])
def protected():
    token = request.cookies.get("token")  # 쿠키에서 JWT 가져오기

    if not token:
        return jsonify({"message": "토큰이 없습니다!"}), 403

    try:
        data = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
        return jsonify({"message": f"환영합니다, {data['user']}!"})
    except jwt.ExpiredSignatureError:
        return jsonify({"message": "토큰이 만료되었습니다!"}), 403
    except jwt.InvalidTokenError:
        return jsonify({"message": "유효하지 않은 토큰입니다!"}), 403

if __name__ == "__main__":
    app.run(debug=True)
profile
Bello! NewOld velog~

0개의 댓글