SPRING&BOOT/JPA

JWT란?

jki09871 2024. 8. 30. 00:55
JWT(Json Web Token)는 JSON 객체를 사용하여 두 개체 간에 정보를 안전하게 전송하기 위한 웹 표준(RFC 7519)이다. 주로 인증(authentication)과 권한 부여(authorization)에 사용되며, 클라이언트와 서버 간의 안전한 데이터 교환을 위해 설계되었다. JWT는 세션을 서버에 저장하지 않고도 상태를 유지할 수 있게 해주는 토큰 기반 인증 방식으로, RESTful API와 같은 무상태(stateless) 통신에서 널리 활용되고 있다.

JWT의 구조

JWT는 Header, Payload, Signature의 세 부분으로 구성된 문자열이다. 이 세 부분은 각각 Base64Url로 인코딩되어 마침내 .으로 구분된 하나의 문자열로 결합된다. 이 구조 덕분에 JWT는 가볍고, 웹에서 쉽게 사용할 수 있다.

 

1. Header:

  • Header는 JWT의 메타데이터를 포함한다. 주로 토큰의 유형(typ)과 사용할 서명 알고리즘(alg)을 명시한다.
  • 예를 들어, HS256(HMAC SHA256) 알고리즘을 사용한다고 하면, Header는 다음과 같이 표현된다.
{
  "alg": "HS256",
  "typ": "JWT"
}

 

2. Payload:

  • Payload는 실제 토큰에 담길 데이터를 포함한다. 이 데이터를 클레임(Claim)이라고 부르며, 클레임에는 다음과 같은 유형이 있다:
    • Registered Claims: JWT 표준에 정의된 클레임으로, iss(issuer), exp(expiration time), sub(subject), aud(audience) 등이 있다. 이러한 클레임들은 필수는 아니지만, 권장된다.
    • Public Claims: 공개적으로 사용할 수 있는 클레임으로, 충돌을 피하기 위해 URI 형식으로 이름을 지정할 수 있다.
    • Private Claims: 애플리케이션 간의 커뮤니케이션에서 사용하기 위해 정의된 클레임으로, 표준이나 공개 클레임과 관계없이 사용자에 의해 정의된다.
{
  "sub": "user123",
  "name": "John Doe",
  "admin": true,
  "iat": 1516239022
}

 

이 JSON 객체 또한 Base64Url로 인코딩되어 JWT의 두 번째 부분을 구성한다.

 

3. Signature:

  • Signature는 JWT의 무결성을 보장하는 역할을 한다. Signature는 Header와 Payload를 인코딩한 문자열을 조합한 후, 주어진 비밀키로 서명하여 생성된다.
  • 서명은 다음과 같이 생성된다:
HMACSHA256(
  base64UrlEncode(header) + "." + base64UrlEncode(payload),
  secret
)

 

이 서명 값을 JWT의 세 번째 부분으로 추가하여 최종 JWT가 생성된다.\

 

JWT의 동작 방식

JWT는 클라이언트와 서버 간의 인증 및 데이터 교환에 주로 사용된다. 일반적인 JWT의 사용 흐름은 다음과 같다:

  1. 사용자 인증:
    • 사용자가 로그인하면, 서버는 사용자 정보를 검증한 후 JWT를 생성한다. 이 JWT는 사용자의 인증 정보와 함께 만료 시간(exp) 등을 포함할 수 있다.
    • 생성된 JWT는 클라이언트(일반적으로 브라우저나 모바일 앱)에게 반환된다.
  2. 클라이언트 저장:
    • 클라이언트는 서버로부터 받은 JWT를 로컬 스토리지나 세션 스토리지, 혹은 쿠키에 저장한다. 이 저장된 토큰은 이후 서버와의 통신에서 인증 수단으로 사용된다.
  3. 인증 요청:
    • 클라이언트가 서버에 요청을 보낼 때, JWT를 HTTP 헤더의 Authorization 필드에 포함시켜 보낸다. 일반적으로 헤더의 값은 Bearer <token> 형식으로 전송된다.
Authorization: Bearer <JWT>
  1. 서버 검증:
    • 서버는 요청을 받으면, 전달된 JWT의 서명을 검증하여 토큰이 조작되지 않았음을 확인한다. 또한, 토큰의 유효 기간이나 클레임들을 확인하여 요청이 유효한지 판단한다.
    • 검증이 완료되면, 서버는 JWT에 포함된 사용자 정보를 기반으로 요청을 처리한다.

JWT의 장점

JWT는 몇 가지 주요한 장점을 제공한다:

  1. 무상태(stateless):
    • JWT는 서버가 별도의 세션 상태를 저장할 필요가 없게 해준다. 모든 필요한 정보가 토큰 자체에 포함되어 있으므로, 서버는 토큰만으로 사용자를 인증할 수 있다. 이는 확장성 있는 애플리케이션을 구축하는 데 매우 유리하다.
  2. 간편한 클라이언트-서버 간 통신:
    • JWT는 클라이언트와 서버 간의 상태를 유지하기 위해 가벼운 토큰을 사용하므로, HTTP 헤더에 쉽게 포함되어 전송될 수 있다. 이로 인해 RESTful API와 같은 무상태 서비스에 적합하다.
  3. 보안성:
    • JWT는 서명을 통해 토큰의 무결성을 보장한다. 서명 덕분에, 중간에서 토큰의 데이터를 조작하는 것이 어렵다. 또한, 클라이언트에서 데이터를 암호화하여 사용하면, 더 높은 수준의 보안을 제공할 수 있다.
  4. 다양한 클레임:
    • JWT는 다양한 정보를 클레임으로 담을 수 있다. 사용자 인증 정보 외에도, 사용자 권한, 역할, 세션 정보 등을 포함할 수 있어 유연성이 높다.

JWT의 단점

JWT는 장점이 많지만, 몇 가지 단점도 존재한다:

  1. 토큰 크기:
    • JWT는 세션 쿠키보다 크기가 크다. Header, Payload, Signature가 모두 Base64Url로 인코딩되기 때문에, 트래픽이 증가할 수 있다. 특히, 대규모의 정보를 JWT에 담을 경우, 네트워크 대역폭에 부정적인 영향을 줄 수 있다.
  2. 만료 후 처리 문제:
    • JWT는 한 번 발급되면 만료 시간(exp)까지 유효하다. 이 말은, 발급된 JWT는 서버에서 강제로 무효화할 수 없다는 것을 의미한다. 따라서 보안적으로 중요한 시스템에서는 토큰의 만료 시간을 짧게 설정하거나, 서버 측에서 별도의 블랙리스트를 관리해야 할 필요가 있다.
  3. 민감한 정보 취급:
    • JWT의 Payload는 Base64Url로 인코딩되어 있지만, 암호화된 것은 아니다. 즉, 토큰을 탈취한 공격자는 인코딩된 데이터를 쉽게 디코딩할 수 있다. 따라서 민감한 정보를 JWT에 담는 것은 위험할 수 있으며, 반드시 필요한 경우에는 암호화를 사용하는 것이 좋다.
  4. 서명 검증 부하:
    • 서버는 클라이언트로부터 받은 JWT를 검증해야 한다. 이 과정에서 서명 검증이 이루어지는데, 서버가 많은 요청을 처리해야 하는 상황에서는 이 검증 과정이 성능에 영향을 줄 수 있다.

JWT 사용 시 고려할 점

JWT를 사용할 때는 몇 가지 중요한 점을 고려해야 한다:

  1. 짧은 만료 시간 설정:
    • 토큰 탈취 시 피해를 최소화하기 위해, JWT의 만료 시간을 가능한 짧게 설정하는 것이 좋다. 만료 시간이 짧으면, 공격자가 토큰을 탈취하더라도 그 토큰의 유효 시간이 빠르게 끝나 피해를 줄일 수 있다.
  2. HTTPS 사용:
    • JWT는 서명만으로 무결성을 보장하지만, 전송 중 도청을 막을 수는 없다. 따라서 JWT를 전송할 때는 반드시 HTTPS를 사용하여 전송 중간에서 탈취되는 것을 방지해야 한다.
  3. 리프레시 토큰 사용:
    • 짧은 만료 시간을 설정하면, 사용자가 자주 로그아웃되는 문제가 발생할 수 있다. 이를 해결하기 위해 리프레시 토큰(refresh token)을 사용하여 JWT의 수명을 연장하는 방법을 고려할 수 있다. 리프레시 토큰은 일반적으로 더 긴 수명을 가지며, 주기적으로 새로운 JWT를 발급받는 데 사용된다.
  4. 추가적인 보안 검토:
    • JWT에 민감한 정보를 포함시킬 때는 반드시 해당 데이터를 암호화하는 등의 추가적인 보안 조치를 고려해야 한다. 또한, JWT 사용 시 블랙리스트 관리, 토큰 재사용 방지 등을 통해 보안을 강화할 필요가 있다.

결론

JWT는 현대적인 웹 애플리케이션에서 매우 유용한 인증 및 권한 부여 수단이다. 무상태 특성과 보안성을 기반으로 다양한 서비스에서 사용되고 있으며,