RFC 7519
RFC 7519는 JSON Web Token(JWT)에 대한 공식 인터넷 표준 문서이다.
2015년 5월에 Internet Engineering Task Force(IETF)에 의해 발행된 이 문서는 JWT의 구조, 형식, 서명 방법, 암호화 방법 등을 상세히 정의하고 있다. JWT는 당사자 간에 안전하게 정보를 전송하기 위한 간결하고 자체 포함적인 방법을 제공하는 개방형 표준이다.
JWT는 현대 웹 애플리케이션과 마이크로서비스 아키텍처에서 인증 및 정보 교환을 위한 핵심 기술로 자리 잡았다. 특히 Single Sign-On(SSO), API 인증, 정보의 안전한 전송 등 다양한 사용 사례에서 널리 활용되고 있다.
RFC 7519는 Michael B. Jones, John Bradley, Nat Sakimura가 작성했으며, JWT의 기반이 되는 JSON Web Signature(JWS, RFC 7515) 및 JSON Web Encryption(JWE, RFC 7516) 표준과 밀접하게 연관되어 있다.
JWT의 기본 개념과 구조
JWT의 정의
JWT는 당사자 간에 클레임(claim)을 안전하게 표현하기 위한 컴팩트하고 URL-safe한 수단이다. 클레임이란 어떤 주체(subject)에 대한 진술이나 정보를 의미한다. 예를 들어, 사용자의 신원, 권한, 또는 기타 데이터 등이 클레임에 포함될 수 있다.
JWT의 기본 구조
JWT는 세 부분으로 구성되며, 각 부분은 점(.)으로 구분된다:
|
|
이 세 부분은 각각 다음과 같다:
- 헤더(Header): JWT의 유형과 사용된 서명 알고리즘을 지정한다.
- 페이로드(Payload): 전송하려는 클레임들을 포함한다.
- 서명(Signature): 토큰의 무결성을 검증하기 위한 서명 부분이다.
각 부분은 Base64Url로 인코딩되어 있어, URL에서 안전하게 사용할 수 있다.
헤더(Header)
헤더는 일반적으로 두 가지 정보를 담고 있다:
typ
(Type): 토큰의 유형을 지정한다. 일반적으로 “JWT"이다.alg
(Algorithm): 서명 생성에 사용된 알고리즘을 지정한다. 예: HMAC SHA256 (HS256), RSA SHA256 (RS256) 등
예시:
페이로드(Payload)
페이로드는 토큰이 전달하려는 클레임들을 포함한다.
RFC 7519는 클레임을 세 가지 유형으로 분류한다:
- 등록된 클레임(Registered Claims): 미리 정의된 클레임으로, 필수는 아니지만 권장된다.
iss
(Issuer): 토큰 발급자sub
(Subject): 토큰 제목aud
(Audience): 토큰 대상자exp
(Expiration Time): 토큰 만료 시간nbf
(Not Before): 이 시간 이전에는 토큰이 유효하지 않음iat
(Issued At): 토큰 발급 시간jti
(JWT ID): 토큰의 고유 식별자
- 공개 클레임(Public Claims): JWT 사용자가 정의할 수 있지만, 충돌 방지를 위해 IANA JSON Web Token Registry에 등록하거나 충돌 방지 이름(Collision-Resistant Name)을 포함해야 한다.
- 비공개 클레임(Private Claims): 사용 당사자 간에 정보를 공유하기 위해 생성된 맞춤형 클레임이다.
예시:
서명(Signature)
서명은 JWT의 무결성을 검증하고 발신자를 인증하는 데 사용된다. 서명은 인코딩된 헤더, 인코딩된 페이로드, 비밀 키, 헤더에 지정된 알고리즘을 사용하여 생성된다.
예를 들어, HMAC SHA256 알고리즘을 사용하는 경우:
이 서명은 메시지가 도중에 변경되지 않았는지 확인하는 데 사용되며, 비밀 키로 서명된 토큰의 경우 발신자의 신원도 확인할 수 있다.
JWT의 서명 및 암호화 알고리즘
RFC 7519는 JWT의 서명과 암호화를 위한 여러 알고리즘을 지원한다.
서명 알고리즘
JWT는 다양한 서명 알고리즘을 지원하며, 주요 알고리즘은 다음과 같다:
- HMAC(Hash-based Message Authentication Code) 알고리즘:
- HS256: HMAC using SHA-256
- HS384: HMAC using SHA-384
- HS512: HMAC using SHA-512
- RSA(Rivest-Shamir-Adleman) 알고리즘:
- RS256: RSA Signature with SHA-256
- RS384: RSA Signature with SHA-384
- RS512: RSA Signature with SHA-512
- ECDSA(Elliptic Curve Digital Signature Algorithm) 알고리즘:
- ES256: ECDSA using P-256 curve and SHA-256
- ES384: ECDSA using P-384 curve and SHA-384
- ES512: ECDSA using P-521 curve and SHA-512
- 무서명 JWT:
none
: 서명 없음 (보안상의 이유로 일반적으로 권장되지 않음)
각 알고리즘의 특징 및 적용 사례
- HMAC 기반 알고리즘:
- 대칭 암호화 방식으로, 동일한 비밀 키를 사용하여 서명 생성 및 검증
- 구현이 간단하고 빠른 성능
- 주로 단일 시스템 내에서 사용되거나 안전하게 비밀 키를 공유할 수 있는 경우에 적합
- 사용 사례: 동일한 조직 내 서비스 간 통신
- RSA 기반 알고리즘:
- 비대칭 암호화 방식으로, 개인 키로 서명을 생성하고 공개 키로 검증
- 키 배포가 더 안전함 (공개 키는 공개적으로 공유 가능)
- 상대적으로 더 많은 컴퓨팅 리소스 필요
- 사용 사례: 여러 클라이언트가 토큰을 검증해야 하는 공개 API
- ECDSA 기반 알고리즘:
- 비대칭 암호화 방식으로, RSA와 유사하지만 더 작은 키 크기로 동등한 보안 제공
- 더 높은 성능과 더 작은 서명 크기
- 사용 사례: 모바일 애플리케이션, IoT 디바이스 등 리소스 제약이 있는 환경
암호화 알고리즘
JWT는 JWE(JSON Web Encryption) 사양을 통해 페이로드 암호화를 지원한다.
주요 암호화 알고리즘은 다음과 같다:
- 키 암호화 알고리즘:
- RSA1_5: RSAES-PKCS1-v1_5
- RSA-OAEP: RSAES OAEP using default parameters
- A128KW, A192KW, A256KW: AES Key Wrap with 128, 192, 256-bit keys
- 콘텐츠 암호화 알고리즘:
- A128CBC-HS256: AES CBC mode with HMAC SHA-256
- A192CBC-HS384: AES CBC mode with HMAC SHA-384
- A256CBC-HS512: AES CBC mode with HMAC SHA-512
- A128GCM, A192GCM, A256GCM: AES GCM mode with 128, 192, 256-bit keys
암호화된 JWT(JWE)는 다섯 부분으로 구성되며, 각 부분은 점(.)으로 구분된다:
|
|
JWT의 보안 고려사항
RFC 7519는 JWT 사용 시 고려해야 할 여러 보안 사항을 명시하고 있다.
알고리즘 선택과 관련된 보안 문제
- 알고리즘 강제(Algorithm Forcing) 공격:
- 공격자가
alg
값을none
으로 변경하여 서명 검증을 우회하려는 시도 - 방어:
none
알고리즘 사용을 명시적으로 금지하고, 예상되는 알고리즘을 강제 적용
- 공격자가
- 알고리즘 교체(Algorithm Substitution) 공격:
- 공격자가 알고리즘을 대칭키(HMAC)에서 비대칭키(RSA)로 변경하여 공개키를 비밀키로 사용하게 하는 공격
- 방어: 토큰 검증 시 사용할 알고리즘을 미리 결정하고 고정
토큰 수명 관리
- 만료 시간 설정:
- 모든 JWT에 적절한 만료 시간(
exp
클레임)을 설정해야 함 - 애플리케이션 요구사항에 따라 짧게(몇 분에서 몇 시간) 설정하는 것이 좋음
- 모든 JWT에 적절한 만료 시간(
- 토큰 갱신(Refresh) 메커니즘:
- 짧은 만료 시간을 가진 액세스 토큰과 더 긴 만료 시간을 가진 갱신 토큰의 조합 사용
- 액세스 토큰이 만료되면 갱신 토큰을 사용하여 새 액세스 토큰 발급
토큰 저장 및 전송
- 클라이언트 측 저장:
httpOnly
플래그가 설정된 쿠키에 저장(XSS 공격으로부터 보호)Secure
플래그를 사용하여 HTTPS를 통해서만 전송SameSite
속성을 설정하여 CSRF 공격 방지
- 토큰 전송:
- Authorization 헤더를 통한 전송:
Authorization: Bearer <token>
- 쿼리 파라미터로 전송하는 것은 보안상 권장되지 않음(로그에 노출될 수 있음)
- Authorization 헤더를 통한 전송:
페이로드 보안
민감한 정보 처리:
- JWT의 페이로드는 단순히 Base64Url로 인코딩되어 있어 누구나 디코딩할 수 있음
- 비밀번호, 개인식별정보 등 민감한 정보는 포함하지 않아야 함
- 민감한 정보가 필요한 경우 JWE를 사용하여 페이로드 전체를 암호화해야 함
토큰 크기 관리:
- 페이로드에 너무 많은 정보를 포함하면 토큰 크기가 커져 성능에 영향을 미칠 수 있음
- 필요한 최소한의 정보만 포함하는 것이 좋음
서명 검증
- 서명 무결성 보장:
- 모든 JWT 검증 시 서명을 철저히 검증해야 함
- 서명 검증을 건너뛰지 않도록 주의
- 키 관리:
- 서명 및 암호화에 사용되는 키를 안전하게 관리
- 정기적인 키 교체(rotation) 메커니즘 구현
JWT 클레임(Claims)의 상세 설명
RFC 7519는 JWT에서 사용할 수 있는 여러 표준 클레임을 정의하고 있습니다. 이러한 클레임은 토큰에 대한 메타데이터와 조건을 제공합니다.
5.1 등록된 클레임(Registered Claims)
등록된 클레임은 상호 운용성을 위해 IANA JWT Claims Registry에 등록된 미리 정의된 클레임입니다:
iss
(Issuer):- 토큰을 발행한 주체(발급자)를 식별
- 일반적으로 URL 형식의 문자열(예: “https://auth.example.com”)
- 수신자는 이 값을 사용하여 특정 발급자로부터의 토큰만 수락하도록 제한 가능
sub
(Subject):- 토큰이 나타내는 주체(일반적으로 사용자)를 식별
- 발급자 내에서 고유해야 함(예: 사용자 ID)
- 수신자는 이 값을 사용하여 특정 사용자와 관련된 작업을 수행
aud
(Audience):- 토큰의 의도된 수신자를 식별
- 문자열 또는 문자열 배열 가능
- 수신자는 자신이 이 목록에 포함되어 있는지 확인해야 함
exp
(Expiration Time):- 토큰이 만료되는 시간(NumericDate 형식, Unix 시간(초))
- 이 시간 이후에는 토큰이 거부되어야 함
- 약간의 시계 편차(일반적으로 몇 분)를 허용하는 것이 좋음
nbf
(Not Before):- 토큰이 유효해지는 시작 시간(NumericDate 형식)
- 이 시간 이전에는 토큰이 거부되어야 함
- 미래 시간으로 설정하여 토큰의 사용을 지연시킬 수 있음
iat
(Issued At):- 토큰이 발행된 시간(NumericDate 형식)
- 토큰의 나이를 결정하는 데 사용 가능
- 토큰 갱신 정책에 활용 가능
jti
(JWT ID):- 토큰의 고유 식별자
- 중복 처리, 재생 공격 방지 등에 사용
- 발급자는 각 토큰에 고유한 값을 할당해야 함
5.2 공개 클레임(Public Claims)
공개 클레임은 JWT 사용자가 정의할 수 있지만, 이름 충돌을 방지하기 위한 조치가 필요합니다:
IANA JWT Claims Registry에 등록:
- 표준화된 클레임 사용을 위해 공식 레지스트리에 등록
- 예:
name
,email
,preferred_username
등
충돌 방지 이름(Collision-Resistant Name) 사용:
- 도메인 이름을 접두사로 사용(예:
https://example.com/claims/role
) - URI 형식으로 정의하여 충돌 방지
- 도메인 이름을 접두사로 사용(예:
공개 클레임의 예:
5.3 비공개 클레임(Private Claims)
비공개 클레임은 당사자 간에 합의된 정보를 공유하기 위한 맞춤형 클레임입니다:
- 등록된 클레임이나 공개 클레임과 충돌하지 않는 이름 사용
- 발급자와 소비자 간에 의미가 이해되어야 함
- 일반적으로 특정 애플리케이션이나 컨텍스트에 한정된 정보
비공개 클레임의 예:
6. JWT 사용 패턴 및 모범 사례
RFC 7519와 업계 모범 사례를 기반으로 한 JWT의 효과적인 사용 패턴을 살펴보겠습니다.
6.1 인증 및 권한 부여 패턴
액세스 토큰/갱신 토큰 패턴:
- 짧은 수명의 액세스 토큰(몇 분
몇 시간)과 긴 수명의 갱신 토큰(며칠몇 주) 사용 - 액세스 토큰이 만료되면 갱신 토큰을 사용하여 새 액세스 토큰 발급
- 갱신 토큰은 데이터베이스에 저장하고 필요시 취소 가능하게 관리
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
클라이언트 서버 | | |-- 로그인 (username, password) --> | | | |<-- 액세스 토큰 + 갱신 토큰 ------| | | |-- 요청 + 액세스 토큰 -----------> | |<-- 응답 ------------------------- | | | |-- 요청 + 만료된 액세스 토큰 ----> | |<-- 401 Unauthorized ------------- | | | |-- 갱신 요청 + 갱신 토큰 --------> | |<-- 새 액세스 토큰 + 새 갱신 토큰 -| | |
- 짧은 수명의 액세스 토큰(몇 분
상태 비저장(Stateless) JWT vs. 상태 저장(Stateful) JWT:
- 상태 비저장: 토큰에 모든 필요한 정보 포함, 서버에 저장 안 함
- 장점: 확장성 좋음, 데이터베이스 조회 불필요
- 단점: 토큰 취소 어려움, 크기가 클 수 있음
- 상태 저장: 토큰에 최소한의 정보만 포함하고 서버에 나머지 정보 저장
- 장점: 토큰 취소 용이, 작은 토큰 크기
- 단점: 데이터베이스 조회 필요, 복잡한 구현
- 상태 비저장: 토큰에 모든 필요한 정보 포함, 서버에 저장 안 함
자체 포함(Self-contained) 권한:
JWT에 사용자 역할, 권한 등을 포함하여 별도 조회 없이 권한 부여 결정
예:
1
{ "sub": "1234567890", "roles": ["admin", "editor"], "permissions": ["read:users", "write:users"]}
6.2 토큰 관리 모범 사례
적절한 만료 시간 설정:
- 액세스 토큰: 15분~2시간 (보안 요구사항에 따라 조정)
- 갱신 토큰: 7일~30일 (필요에 따라 조정)
- 위험도가 높은 작업은 더 짧은 만료 시간 적용
토큰 취소 메커니즘:
- 블랙리스트: 취소된 토큰의 jti를 저장하여 검증 시 확인
- 화이트리스트: 유효한 토큰만 목록에 유지
- Redis와 같은 인메모리 데이터 저장소 사용 권장
키 관리(Key Management):
- 정기적인 키 교체(rotation) 구현 (일반적으로 3~6개월마다)
- 키 ID(
kid
) 헤더 파라미터 사용하여 여러 키 관리 - HSM(Hardware Security Module) 또는 KMS(Key Management Service) 사용 권장
토큰 크기 최적화:
- 필요한 최소한의 클레임만 포함
- 긴 클레임 이름 대신 짧은 이름 사용 고려
- 중요한 메타데이터에만 등록된 클레임 사용
6.3 보안 강화 방법
서명 알고리즘 권장사항:
- 대칭 키: HS256 이상 사용(HS384, HS512 권장)
- 비대칭 키: RS256 이상 또는 ES256 이상 권장
- 알고리즘 없음(
"alg": "none"
)은 절대 사용 금지
토큰 사용 제한:
aud
클레임을 사용하여 특정 서비스만 토큰을 사용하도록 제한scope
또는scp
클레임을 사용하여 토큰의 권한 범위 제한
CSRF 및 XSS 방어:
- JWT를
httpOnly
및Secure
플래그가 설정된 쿠키에 저장 SameSite=Strict
또는SameSite=Lax
쿠키 설정 사용- 브라우저 내 스토리지(localStorage, sessionStorage)를 사용할 경우 XSS 대비 강화
- JWT를
토큰 무결성 검증:
- 모든 필수 클레임 존재 여부 검증
- 예상되는 발급자(
iss
), 대상(aud
) 확인 - 토큰 유형(
typ
) 확인
JWT 구현 예제
다양한 프로그래밍 언어에서 JWT를 구현하는 방법
Node.js에서의 JWT 구현
jsonwebtoken 라이브러리를 사용한 예제:
|
|
Python에서의 JWT 구현
PyJWT 라이브러리를 사용한 예제:
|
|
Java에서의 JWT 구현
jjwt 라이브러리를 사용한 예제:
|
|
8. JWT 관련 도구 및 라이브러리
JWT 작업을 위한 유용한 도구와 라이브러리
디버깅 및 검사 도구
- jwt.io:
- JWT 디코딩, 검증, 생성을 위한 온라인 도구
- 다양한 알고리즘 지원
- 토큰 구조 시각화 제공
- JSON Web Token Debugger Chrome Extension:
- 브라우저에서 직접 JWT 디코딩 및 검사
- 개발 및 디버깅 시 유용
- JWT Validator:
- JWT 검증 도구
- 다양한 서명 알고리즘 지원
주요 JWT 라이브러리
다양한 프로그래밍 언어별 주요 JWT 라이브러리:
- JavaScript/Node.js:
- jsonwebtoken: Node.js에서 가장 인기 있는 JWT 라이브러리
- jose: 완전한 JSON Object Signing and Encryption 구현
- Python:
- PyJWT: 가볍고 사용하기 쉬운 JWT 라이브러리
- python-jose: JWS, JWE, JWK, JWA 구현 포함
- Java:
- C#/.NET:
- System.IdentityModel.Tokens.Jwt:.NET 공식 JWT 라이브러리
- jose-jwt: JWS, JWE, JWK, JWA 구현
- PHP:
- firebase/php-jwt: 간단한 JWT 인코딩/디코딩 라이브러리
- lcobucci/jwt: 더 완전한 구현
- Ruby:
- ruby-jwt: Ruby에서의 JWT 구현
- Go:
- golang-jwt/jwt: Go에서 가장 인기 있는 JWT 구현
JWT 관련 프레임워크 통합
많은 웹 프레임워크와 인증 시스템이 JWT를 지원:
- Spring Security (Java):
- JWT 기반 인증 지원
- OAuth2 및 JWT 통합
- Passport.js (Node.js):
- passport-jwt 전략 제공
- Express.js와 쉽게 통합
- Django REST Framework (Python):
- djangorestframework-simplejwt 패키지
- JWT 인증 제공
- ASP.NET Core (C#):
- 내장 JWT 인증 미들웨어
- 쉬운 설정 및 통합
- Laravel (PHP):
- tymon/jwt-auth 패키지
- JWT 인증 지원
JWT와 관련 표준
JWT는 더 큰 JSON 객체 서명 및 암호화(JOSE) 프레임워크의 일부이다.
JOSE 프레임워크
JSON Object Signing and Encryption(JOSE) 프레임워크는 JSON 데이터 구조를 사용하여 보안 서비스를 제공하는 표준 모음:
- JWS(JSON Web Signature) - RFC 7515:
- JSON 데이터 구조 서명을 위한 표준
- 데이터 무결성과 출처 인증 제공
- JWT의 서명 메커니즘 정의
- JWE(JSON Web Encryption) - RFC 7516:
- JSON 데이터 구조 암호화를 위한 표준
- 기밀성 제공
- JWT의 암호화 메커니즘 정의
- JWK(JSON Web Key) - RFC 7517:
- 암호화 키를 JSON 형식으로 표현하는 표준
- 키 정보 교환에 사용
- 공개 키 인프라(PKI)를 단순화
- JWA(JSON Web Algorithms) - RFC 7518:
- JWS, JWE, JWK에서 사용되는 암호화 알고리즘 정의
- 서명, 암호화, 키 암호화, 콘텐츠 암호화 등을 위한 알고리즘 지정
OpenID Connect와 JWT
JWT는 OpenID Connect(OIDC) 프로토콜의 핵심 구성 요소이다:
- ID 토큰:
- OpenID Connect의 핵심 개념
- 사용자 인증 정보를 포함하는 JWT
iss
,sub
,aud
,exp
,iat
등의 표준 클레임 포함
- UserInfo 응답:
- 선택적으로 JWT 형식으로 제공 가능
- 사용자 프로필 정보 포함
- 클라이언트 등록:
- JWT를 사용한 클라이언트 인증 지원
OAuth 2.0과 JWT
JWT는 OAuth 2.0 프로토콜에서 여러 방식으로 활용된다:
- Bearer 토큰 형식:
- JWT는 OAuth 2.0에서 액세스 토큰으로 사용 가능
- RFC 6750에 정의된 Bearer 토큰 전송 방식 사용
- 클라이언트 인증:
- JWT를 사용한 클라이언트 인증
- RFC 7523에 정의된 JWT 프로필
- 토큰 교환:
- JWT 교환을 위한 OAuth 2.0 확장(JWT Bearer Token Flow)
- 한 도메인의 JWT를 다른 도메인에서 사용 가능한 토큰으로 교환
용어 정리
용어 | 설명 |
---|---|