본문 바로가기

Development/Spring

[Spring] JWT와 Spring Security

JWT(JSON Web Token)

  • JWT는 서로 통신을 하면서 정보를 JSON 형태로 안전하게 전송하기 위한 토큰이다.
  • JWT는 URL로 이용할 수 있는 문자열로만 구성돼 있으며, 디지털 서명이 적용돼 있어 신뢰할 수 있다.
  • JWT는 주로 서버와의 통신에서 권한 인가를 위해 사용된다.
  • URL에서 사용할 수 있는 문자열로만 구성돼 있어 HTTP 구성요소 어디든 위치할 수 있다.

JWT의 구조

JWT는 '.' 으로 구분된 세 부분으로 구성된다.

  • 헤더(Header)
  • 내용(Payload)
  • 서명(Signature)

헤더

  • JWT의 헤더는 검증과 관련된 내용을 포함한다.
  • 헤더에는 alg, typ 속성 두 가지 정보를 포함한다.
{
  "alg": "HS256", // 'HMAC SHA256'
  "typ": "JWT"
}
  • alg 속성에서는 해싱 알고리즘을 지정한다. 해싱 알고리즘은 SHA256, RSA를 사용하며 토큰을 검증할 떄 사용되는 서명 부분에서 사용된다.
  • typ 속성에는 토큰의 타입을 지정한다.
  • 완성된 헤더는 Base64Url 형식으로 인코딩돼 사용된다.

내용

  • JWT의 내용에는 토큰에 담는 정보를 포함한다. 이 정보에 포함된 속성들을 클레임(claim) 이라고 한다.
  • 클레임은 크게 세 가지로 분류된다.

등록된 클레임(Registered Claims)

등록된 클레임은 필수는 아니지만, 토큰에 대한 정보를 담기 위해 이미 이름이 정해져 있는 클레임이다.
등록된 클레임은 다음과 같이 정의된다.

  • iss: JWT의 발급자(Issuer) 주체를 나타낸다. 이 값은 문자열이나 URI를 포함하는 대소문자를 구분하는 문자열이다.
  • sub: JWT의 제목(Subject) 이다.
  • aud: JWT의 수신인(Audience) 이다. JWT를 처리하려는 각 주체는 해당 값으로 자신을 식별해야 한다. 요청을 처리하는 주체가 'aud' 값으로 자신을 식별하지 않으면 JWT는 거부된다.
  • exp: JWT의 만료시간(Expiration) 이다. 시간은 NumericDate 형식으로 지정해야 한다.
  • nbf: "Not Before"을 의미한다.
  • iat: JWT가 발급된 시간(Issued At) 이다.
  • jti: JWT의 식별자(JWT ID)이다. 주로 중복 처리를 방지하기 위해 사용된다.

JWT 내용 예시는 다음과 같다.
완성된 내용은 Base64Url 형식으로 인코딩된다.

{
  "sub": "payload",
  "exp": "1602086408",
  "userId": "kim",
  "username": "kim"

공개 클레임은 키 값을 마음대로 정의할 수 있다. 단, 충돌이 발생하지 않도록 이름을 설정해야 한다.
비공개 클레임은 통신 간에 상호 합의되고 등록된 클레임과 공개된 클레임이 아닌 클레임을 의미한다.

서명

JWT의 서명은 인코딩된 헤더, 인코딩된 내용, 비밀키, 헤더의 알고리즘 속성값을 가져와 생성된다.
HMAC SHA256 알고리즘을 사용해서 서명을 생성하면 다음과 같은 방식으로 생성된다.

HMACSHA256(
base64UrlEncode(header) + "." + 
base64UrlEncode(payload),
secret

서명은 토큰의 값들을 포함해서 암호화하기 때문에 메시지가 도중에 변경되지 않았는지 확인할 때 사용된다.

JWT 디버거

JWT 공식 사이트에서는 쉽게 JWT를 생성할 수 있다.

Spring Security와 JWT

* Google Gemini의 답변

 

Spring Security:

  • 인증, 인가, 세션 관리 등 웹 애플리케이션 보안 기능을 제공하는 Spring Framework 확장 라이브러리
  • 다양한 인증 방식 지원 (OAuth2, LDAP, Kerberos 등)
  • 다양한 권한 설정 및 제어 기능 제공
  • 웹 기반 애플리케이션 보안 강화에 유용

JWT (JSON Web Token):

  • 사용자 정보, 인증 정보 등을 담은 JSON 기반 토큰
  • 서버 사이드에서 발급 및 검증
  • 클라이언트는 요청 시 헤더에 토큰 포함
  • 세션 관리 필요 없음
  • REST API 인증에 유용

Spring Security와 JWT 연동

Spring Security를 사용하여 JWT 기반 인증을 구현할 수 있다.

 

주요 단계:

  1. JWT 토큰 생성: 사용자 로그인 성공 시 사용자 정보를 기반으로 JWT 토큰 생성
  2. JWT 토큰 검증: 모든 요청 헤더에서 토큰 추출 및 서명 검증
  3. 사용자 권한 부여: 토큰 정보 기반 사용자 권한 설정 및 제어

Spring Security JWT 기능:

  • JWT 토큰 생성, 검증, 만료 시간 관리 등 기능 제공
  • 다양한 토큰 저장 방식 지원 (예: 서버 메모리, Redis)
  • 커스텀 토큰 생성 및 검증 로직 설정 가능

Spring Security와 JWT 연동 장점

  • 세션 관리 불필요: 서버에 세션 정보 저장하지 않아 서버 부하 감소
  • 확장성: 다양한 클라이언트 환경에서 사용 가능
  • Stateless: 서버 상태 유지하지 않아 클라우드 환경에 적합
  • 토큰 기반 인증: 쿠키 기반 인증보다 안전

Spring Security와 JWT 연동 단점

  • 토큰 유출 위험: 토큰 유출 시 사용자 정보 노출 가능성
  • 토큰 관리 복잡: 토큰 만료, 갱신 등 관리 필요
  • CSRF 공격 취약: CSRF 공격에 취약할 수 있음

JWT 의존성 추가

Maven

<dependency>
  <groupId>org.springframework.security</groupId>
  <artifactId>spring-security-web</artifactId>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.9.1</version> 
</dependency>

Gradle

dependencies {
  implementation 'org.springframework.security:spring-security-web'
  implementation "io.jsonwebtoken:jjwt:0.9.1"
}

참고로 JJWT (Java JSON Web Token) 는 Java에서 JSON Web Token(JWT)을 생성, 검증, 파싱하는 데 사용되는 오픈소스 라이브러리이다.

참고

  • 스프링 부트 핵심 가이드 "스프링 부트를 활용한 애플리케이션 개발 실무" , 장정우, 2022
  • 구글 Gemini