Development Study/Backend

[JWT] Jin짜 Way렇게 어렵T? 기초 알아보기

  • -
728x90

JWT를 프론트엔드와 백엔드 관점에서 살펴보자

JWT(Json Web Token) 로그인 방법은 클라이언트(프론트엔드)서버(백엔드) 간의 사용자 인증을 수행하는 데 주로 사용됩니다.

이 방법을 사용하면 사용자는 한 번 인증하면 해당 토큰을 계속 사용할 수 있으므로 복잡한 세션 관리를 할 필요가 없습니다.

이에 대한 설명을 프론트엔드와 백엔드의 관점에서 분할해 설명하겠습니다.

 

한글 버전도 만들었어요!

 

프론트엔드

  • 사용자가 프론트엔드에서 로그인 요청을 할 때, 일반적으로 아이디와 비밀번호 등의 정보를 함께 보냅니다.
  • 이는 일반적으로 HTTP POST 요청을 통해 이루어집니다.
  • 로그인 요청이 성공하면 서버는 JWT를 생성하고 이를 HTTP 응답으로 클라이언트에게 보냅니다.
  • 클라이언트(프론트엔드)는 이 토큰을 저장해야 합니다.
  • 이를 위해 일반적으로 쿠키 또는 localStorage 같은 웹 스토리지를 사용합니다.

프론트엔드에서는 로그인 이후에 필요한 모든 API 요청에 이 JWT를 포함해야 합니다.

일반적으로 이는 HTTP 요청Authorization 헤더"Bearer"라는 접두어와 함께 토큰이 포함되어 있습니다.

백엔드

  • 백엔드 서버에서는 먼저 로그인 요청을 받아 사용자의 자격 증명을 검증합니다.
  • 이는 일반적으로 데이터베이스에 저장된 사용자 정보를 참조하여 이루어집니다.
  • 자격 증명이 올바르다면, 백엔드는 JWT를 생성합니다.
  • JWT는 일반적으로 사용자의 아이디와 같은 식별 정보, 토큰의 만료 날짜, 그리고 서버의 비밀 키를 사용해 서명된 데이터를 포함합니다.
  • 백엔드는 생성한 JWT를 HTTP 응답으로 클라이언트에게 보냅니다.
  • 이후로 클라이언트가 보내는 모든 요청은 이 JWT를 포함해야 합니다.

백엔드 서버에서는 이후로 들어오는 모든 요청에 대해 Authorization 헤더를 확인하고, JWT가 존재하고 유효한지 확인합니다.

이 과정에서 JWT가 만료되었거나 변조되었는지를 검사합니다.

JWT가 유효하다면 해당 요청을 수행하고, 그렇지 않다면 권한이 없다는 HTTP 메세지를 보냅니다.

 


 

토큰을 관리하는 방법과 들어가는 정보는 무엇이 있을까?

JWT(Json Web Tokens)은 로그인된 사용자를 인증하는데 사용되며,

일반적으로 토큰에는 다음과 같은 정보(Payload, 페이로드)가 포함됩니다.

 

  1. 등록된 클레임(Registered Claims)
    • 이는 토큰에 대한 정보를 제공하는 일련의 표준 필드입니다.
    • 예를 들어, 'iss' (발급자), 'exp' (만료 시간), 'sub' (주제), 'aud' (대상), 등입니다.
  2. 공개 클레임(Public Claims)
    • 이는 사용자와 관련된 추가 정보를 포함할 수 있는 필드입니다.
    • 예를 들어 사용자의 아이디, 이름, 권한 등이 있습니다.
  3. 비공개 클레임(Private Claims)
    • 이들은 클라이언트와 서버 사이에 합의하여 사용하는 클레임입니다.
    • 이러한 클레임은 등록된 클레임이나 공개 클레임과 충돌하지 않는 이름을 사용해야 합니다.

 

음, 조금 어려운 것 같네요. 여권에 비유해볼까요?

1. 등록된 클레임(Registered Claims)

  • 여권에는 이름, 성별, 출생일 등의 기본적인 정보가 들어가는데, 이는 "등록된 클레임"에 비유할 수 있습니다.
  • 여권이 이를 통해 누가 소유하고 있는지, 언제 만료되는지 등의 기본적인 정보를 알 수 있는 것처럼, JWT에서 'iss' (발급자), 'exp' (만료 시간), 'sub' (주제), 'aud' (대상) 등의 필드가 바로 이 역할을 합니다.

2. 공개 클레임(Public Claims)

  • 여권에 추가로 특정 사람에게 부여되는 비자나 스탬프와 같은 정보가 추가될 수 있습니다.
  • 이는 해당 사람이 어느 국가로 여행할 수 있는지 또는 어떤 활동을 할 수 있는지에 대한 추가 정보를 제공합니다.
  • 이를 "공개 클레임"에 비유할 수 있습니다.
  • JWT에서 이러한 정보는 사용자의 아이디, 이름, 권한 등을 포함할 수 있습니다.

3. 비공개 클레임(Private Claims)

  • 마지막으로, 여권에는 개인이나 특정 조직이 필요로 하는 추가 정보가 들어갈 수 있습니다.
  • 예를 들어, 특정 여행사가 고객의 여행 선호도나 추가 서비스 등의 정보를 여권에 담아두는 것처럼, JWT에서는 클라이언트와 서버가 합의하여 사용하는 추가 정보가 바로 "비공개 클레임"이 됩니다.
  • 단, 이러한 정보는 기존의 등록된 클레임이나 공개 클레임과는 다른 이름을 사용해야 충돌이 없습니다.

 

그리고 토큰 관리 방법은 여러 가지가 있습니다. 아래 몇 가지 기본적인 방법을 나열해 보겠습니다

  1. 스토리지
    • 토큰은 클라이언트 사이드에서 보안성을 유지하면서도 접근 가능해야 합니다.
    • 일반적으로 이를 위해 HTTP Only 쿠키나 웹 스토리지(Local Storage, Session Storage)를 사용할 수 있습니다.
    • 어떤 방식을 사용하느냐는 **XSS(Cross-Site Scripting)**나 **CSRF(Cross-Site Request Forgery)**와 같은 보안 위협을 어떻게 관리하느냐에 따라 달라집니다.
  2. 만료 관리
    • JWT는 일반적으로 'exp' 클레임을 포함하여 만료 시간을 정의합니다.
    • 서버는 이 만료 시간을 확인하고, 만료된 토큰을 거부해야 합니다.
    • 클라이언트는 만료된 토큰을 감지하고 사용자에게 다시 로그인하거나 토큰을 재발급받을 수 있게 해야 합니다.
  3. 재발급
    • 토큰이 만료되거나 무효화되었을 때, 사용자는 새로운 토큰을 재발급받아야 합니다.
    • 이는 일반적으로 "refresh token"을 사용하여 이루어집니다.
    • Refresh token은 클라이언트가 보안적으로 유효한 상태에서 새로운 access token을 받을 수 있게 해주는 긴 수명을 가진 토큰입니다.
  4. 토큰 무효화
    • 특정 상황에서는 토큰을 무효화해야 할 필요가 있을 수 있습니다.
    • 예를 들어 사용자가 로그아웃하거나, 토큰이 유출되었을 때 등입니다.
    • 이를 위해 몇 가지 방법을 사용할 수 있는데, 예를 들면 토큰을 블랙리스트에 등록하는 것이 있습니다.
    • 이 방식을 사용하면 무효화된 토큰이 더 이상 사용되지 않도록 보장할 수 있습니다.

 


 

비밀번호는 프론트엔드에서 관리하기 힘들지 않을까?

비밀번호와 같은 민감한 정보는 절대로 프론트엔드에서 평문으로 저장해서는 안 됩니다.

보통 사용자가 로그인할 때, 비밀번호는 프론트엔드에서 입력 받아 서버로 전송하게 됩니다.

이때 HTTPS와 같은 보안된 연결을 사용하여 데이터가 전송되는 도중에 노출되는 것을 방지합니다.

 

백엔드에서 비밀번호는 해시와 솔트(salt)를 사용해 보안 처리를 하게 됩니다.

해시는 원래 비밀번호를 알 수 없도록 변환하는 과정이고, 솔트는 해시 과정에 무작위 문자열을 추가해 결과 해시값을 더욱 예측 불가능하게 만드는 과정입니다.

 

이렇게 처리된 비밀번호는 데이터베이스에 저장됩니다.

프론트엔드에서 JWT와 같은 인증 토큰을 저장하는 방법은 여러 가지가 있습니다

  1. 쿠키(Cookies)
    • 쿠키는 웹사이트가 사용자의 브라우저에 저장하는 작은 데이터 조각입니다.
    • HTTP Only 쿠키는 JavaScript를 통해 접근할 수 없으므로 XSS(Cross-Site Scripting) 공격으로부터 안전하다는 장점이 있습니다.
    • 하지만 CSRF(Cross-Site Request Forgery) 공격에 대해 취약할 수 있습니다.
  2. 웹 스토리지(Web Storage)
    • 웹 스토리지에는 두 가지 형태, 즉 로컬 스토리지(Local Storage)와 세션 스토리지(Session Storage)가 있습니다.
    • 이 둘은 쿠키와 비슷하지만, 더 많은 데이터를 저장할 수 있으며 HTTP 요청과 함께 자동으로 서버로 전송되지 않습니다.
    • 웹 스토리지는 XSS 공격에 취약할 수 있지만 적절한 콘텐츠 보안 정책(Content Security Policy)을 통해 이를 완화할 수 있습니다.

어떤 방식을 선택하든 간에, 토큰 저장 방식은 애플리케이션의 보안 요구사항과 관련된 위협 모델에 따라 결정해야 합니다.

 


 

토큰들은 어떤 스펙을 보유하고 있을까?

JWT (JSON Web Tokens)는 Access 토큰과 Refresh 토큰으로 주로 사용되며, 각각 다른 목적과 수명을 가지고 있습니다.

  1. Access 토큰
    • Access 토큰은 사용자가 특정 자원에 접근할 권한을 가지고 있는지를 나타냅니다.
    • 일반적으로 이 토큰은 사용자 세션의 유효성을 나타내며, 짧은 만료 시간을 가집니다 (보통 수 분에서 수 시간).
    • Access 토큰에는 다음과 같은 정보가 포함될 수 있습니다.
      • Subject (sub): 토큰이 대상으로 하는 사용자나 서비스의 ID
      • Issuer (iss): 토큰을 발급한 서비스
      • Expiration (exp): 토큰이 만료되는 시간
      • Not Before (nbf): 이 시간 이전에는 토큰이 처리되지 않아야 함을 나타냅니다.
      • Issued At (iat): 토큰이 발급된 시간
  2. Refresh 토큰
    • Refresh 토큰은 Access 토큰이 만료되었을 때 새로운 Access 토큰을 발급받는 데 사용됩니다.
    • 이 토큰은 보통 긴 수명을 가지고 있으며, 경우에 따라 만료되지 않을 수도 있습니다.
    • Refresh 토큰은 일반적으로 사용자가 로그인 상태를 유지하면서 새로운 Access 토큰을 안전하게 받을 수 있도록 도와줍니다.


Refresh 토큰은 주로 저장소(예: 데이터베이스)에 저장되며, Access 토큰을 발급할 때 이 토큰이 유효한지를 확인합니다.
이렇게 하면, Refresh 토큰이 무효화되거나 임의로 만료될 수 있으므로 더욱 안전한 사용자 세션 관리를 할 수 있습니다.

 

저는 이해가 잘 안되는 것 같아요. 이것도 다른 방법으로 설명해주실 수 있나요?

물론입니다. 이를 설명하기 위해 "회원 카드와 재발급 쿠폰"이라는 개념을 이용하겠습니다.

1. Access 토큰

이는 여러분이 상점에 갈 때 마다 자신이 회원임을 증명하기 위해 보여주는 회원 카드에 비유할 수 있습니다.

이 카드를 통해 자신이 상점의 회원임을 증명하고, 회원 권한을 가진 사람이 사용할 수 있는 특정 상품이나 서비스에 접근할 수 있게 됩니다.

그러나 회원 카드는 일정 기간 후에 만료가 되는데, 이는 보통의 Access 토큰이 짧은 만료 시간을 가지고 있는 것과 같습니다.

Access 토큰에는 발급자, 대상, 만료 시간 등의 정보가 포함되어 있어, 이를 검증하는 측이 해당 토큰이 유효한지 판단할 수 있게 해줍니다.

2. Refresh 토큰

이는 회원 카드가 만료된 후 새로운 카드를 발급받기 위해 사용하는 재발급 쿠폰에 비유할 수 있습니다.

이 쿠폰은 일반적으로 회원 카드보다 훨씬 긴 수명을 가지고 있으며, 이를 통해 새로운 회원 카드를 안전하게 발급받을 수 있습니다.

마찬가지로, Refresh 토큰은 Access 토큰이 만료되었을 때 새로운 Access 토큰을 안전하게 발급받을 수 있도록 도와줍니다.

따라서 사용자는 Access 토큰을 이용해서 자신의 권한을 증명하고 필요한 서비스에 접근할 수 있으며, 만약 Access 토큰이 만료되었다면 Refresh 토큰을 이용해 새로운 Access 토큰을 발급받을 수 있습니다. 

이런 방식으로 JWT 기반의 인증 시스템은 사용자의 인증 상태를 유지하고, 필요한 권한을 부여하는 역할을 수행합니다.

 


 

추가적으로 JWT에 대해 더 알면 좋을 내용들

JWT에 대해 더 얘기해볼 만한 주제들이 몇 가지 있습니다. 보안, JWT 구조, 그리고 JWT의 장단점을 포함해서요.

  1. JWT의 구조
    • JWT는 세 부분으로 이루어져 있습니다: 헤더(Header), 페이로드(Payload), 그리고 서명(Signature).
      • 헤더(Header)는 토큰의 타입과 사용된 알고리즘을 명시합니다.
        • 예를 들어, { "alg": "HS256", "typ": "JWT" }.
      • 페이로드(Payload)에는 클레임(claim)이라 불리는 선언들이 들어 있습니다.
        • 이는 사용자에 대한 데이터나 다른 토큰 관련 정보들을 담고 있습니다.
      • 서명(Signature)은 서버가 헤더와 페이로드를 검증할 수 있게 하는 부분입니다.
        • 서명은 헤더, 페이로드, 그리고 비밀키를 이용해 생성되며, 이 비밀키는 서버에서만 알고 있습니다.
    이 세 부분은 각각 Base64Url로 인코딩되어 .으로 연결된 문자열을 형성합니다.
  2. JWT의 장점과 단점
    • JWT는 Stateless한 성격으로 인해 수평 확장성이 뛰어나고, 서버의 리소스를 적게 사용하는 장점이 있습니다.
    • 하지만 토큰 자체가 정보를 가지고 있기 때문에, 한 번 발급된 토큰은 만료 시간이 지나기 전까지는 무효화하기 어렵다는 단점도 있습니다.
  3. 보안
    • JWT는 보안적으로 매우 중요한 역할을 하기 때문에, 올바르게 관리하고 사용하는 것이 중요합니다.
    • 특히 HS256 (HMAC with SHA-256)와 RS256 (RSA with SHA-256) 같은 강력한 암호화 알고리즘이 사용되어야 하며, 토큰을 보호하기 위해 HTTPS와 같은 보안 프로토콜 위에서 전송되어야 합니다.
    • 또한, 토큰은 안전한 저장소에 저장되어야 하며, 가능한 XSS와 CSRF 같은 공격으로부터 보호되어야 합니다.
  4. JWT에 대한 공격 시나리오와 대응 방안
    • 비밀키 노출
      • JWT는 비밀키를 통해 서명되므로, 이 키가 노출되면 공격자가 임의의 토큰을 만들 수 있습니다.
      • 이를 방지하려면 비밀키를 안전하게 보관하고, 정기적으로 키를 교체해야 합니다.
    • Replay Attacks
      • 만약 토큰이 노출되면, 공격자는 그 토큰을 사용해 서버에게 자신을 해당 사용자로 가장할 수 있습니다.
      • 이를 방지하려면, 토큰을 HTTPS 같은 보안 프로토콜을 통해 전송하고, 가능한 쿠키에 저장하면 좋습니다.
  5. JWT와 OAuth
    • JWT는 OAuth와 같은 인증 프로토콜에서 토큰으로 사용될 수 있습니다.
    • OAuth는 사용자가 인증 정보를 직접 제공하지 않고도, 인증 제공자(ex. Google, Facebook 등)를 통해 서드 파티 애플리케이션에 인증할 수 있게 하는 프로토콜입니다.
    • 이때 인증 제공자는 JWT를 생성하여 애플리케이션에 제공하고, 애플리케이션이 이 JWT를 사용하여 사용자를 인증하게 됩니다.
  6. JWT 디버깅 및 테스팅 도구
    • jwt.io와 같은 웹사이트는 JWT를 생성하고 디코딩하는 데 도움이 됩니다.
    • 이는 JWT를 이해하거나 디버깅하는데 유용한 도구입니다.

JWT.IO

 

JWT.IO

JSON Web Tokens are an open, industry standard RFC 7519 method for representing claims securely between two parties.

jwt.io

이러한 주제 외에도 JWT의 사용 사례, 다른 인증 방법과의 비교, 다양한 프로그래밍 언어에서의 JWT 라이브러리 사용 방법 등이 있습니다.

하지만 우선 기초적인 부분은 이정도면 충분한 것 같습니다.

여기까지 읽느라 고생많으셨습니다.


End

728x90
Contents

포스팅 주소를 복사했습니다

이 글이 도움이 되었다면 공감 부탁드립니다.