JWT
: JSON 형식의 데이터를(Claim) Base64URL 인코딩으로 직렬화한 후 서명해 저장하는 토큰이다.
- Base64 URL Encode: URL을 Base64 방식으로 인코딩할 때 오류를 방지하기 위해 '+'와 '/'를 '-'와 '_'로 표현하는 방식이다.
JWT 구조
: XXXXXX.YYYYYY.ZZZZZZ (Header.Payload.Signature)
- 예시:
1. Header
: 일반적으로 사용한 서명 알고리즘과 토큰 타입으로 구성되어 있다. JSON 형식의 해당 정보를 Base64URL 방식으로 인코딩하여 JWT의 앞 부분을 구성한다.
- 서명 알고리즘: HMAC SHA256 또는 RSA 등...
- 토큰 타입: JWT
- 누구나 읽을 수 있기 때문에 암호화 되지 않은 보안에 민감한 정보를 포함하지 않는다.(암호화가 필요하면 JWE 사용)
{
"alg": "HS256",
"typ": "JWT"
}
2. Payload
: Claim을 담고 있다. Payload를 Base64Url 방식으로 인코딩하여 JWT의 두 번째 부분을 구성한다.
- 누구나 읽을 수 있기 때문에 암호화 되지 않은 보안에 민감한 정보를 포함하지 않는다. (암호화가 필요하면 JWE 사용)
- Claim: key-value로 이뤄진 정보이다.
- Claim 종류
1) Registered claims(표준 정의)
- 선정의된 클레임으로 iss(발급자), exp(만료 시간), sub(제목), iat(발행 시간), aud(토큰 대상자), jti(토큰 고유 식별자)
등에 대한 정보이다.
2) Public claims(사용자 정의 가능)
- 사용자가 정의할 수 있으나 다른 클레임과의 충돌을 피하기 위해 IANA JSON Web Token Registry에 정의된 이름을 사용하거나 충돌을 피할 수 있는 네임스페이스를 포함하는 URI로 정의한다.
- 공개 목적의 정보 전달을 위해 사용한다.
3) Private claims(사용자 정의)
- 당사자 간 정보 공유하기 위해 만들어진 커스텀 claim이다.
- 사용자에 대한 정보이다.
{
"sub": "1234567890", //registered claim
"name": "John Doe", //private claim
"admin": true //private claim
}
3. Signature
: 인코딩된 헤더와 인코딩된 페이로드, 시크릿 키(서버 키)나 개인/공개 키를 헤더에서 정의한 알고리즘을 이용해 서명한다.
- 위변조 검증용이다.
- 예시: HMAC SHA256 알고리즘을 사용
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret
)
JWT의 필요
1. 위변조 방지
- 사용자의 데이터는 Payload에 담겨있는데 다른 사람들이 쉽게 디코딩할 수 있기 때문에 누구나 읽을 수 있다. 정보가 쉽게 노출되어버리는 문제 때문에 보안을 장담할 수 없는 우려가 발생하는데 왜 토큰을 사용할까?
-> 위변조가 발생해도 시크릿 키가 없으면 서명 검증 과정에서 실패하기 때문에 위변조를 방지할 수 있다.
2. 확장성 탁월
- DB 조회를 줄일 수 있다.
JWT 장점
- 별도의 토큰 저장소가 필요없다.
- Payload를 갖고 생성되기 때문에 db 조회를 하지 않아도 된다.
- Payload에 인증 인가 정보를 담아두면 db 조회를 해서 사용자의 권한 정보를 파악하는 과정을 생략할 수 있.
- 서버가 클라이언트 인증 정보를 저장할 필요가 없어 무상태가 되기 때문에 탁월한 확장성을 갖는다.
JWT 단점
- 토큰 길이가 늘어날수록 네트워크 부하의 우려가 있다.
- 토큰을 강제로 만료시키기가 어렵다.
- 토큰이 사용자 정보를 포함해 보안의 우려가 있다.
- 토큰을 탈취 당했을 때 대처가 어렵다.
토큰의 보안을 어떻게 강화할까?
1. 토큰 만료 시간
- 토큰 만료 시간을 짧게 설정하여 해당 시간이 지나면 토큰의 유효성이 사라지도록 한다. 이후 다시 인증 절차를 거쳐야한다.
2. Access 토큰과 Refresh 토큰, Refresh Token Rotation
- Access 토큰: 주로 API 통신 시 사용하는 만료 기간이 짧은 토큰이다.
- Refresh 토큰: 주로 토큰 갱신(재발급)을 용도로 사용하는 만료기간이 긴 토큰이다.
1) 인증 과정 후 서버로부터 Access 토큰과 Refresh 토큰을 발급받아 클라이언트의 로컬에 저장한다.
2) Access 토큰이 만료될 때마다 Refresh 토큰을 사용해 Access Token을 재발급 받는다.
3) Refresh 토큰이 만료되면 인증 과정을 다시 거친다.
Refresh 토큰은 Access 토큰 재발급의 용도로만 사용하기 때문에 통신 빈도가 적긴 하지만 여전히 탈취의 위험이 존재한다.
따라서 Access Token 재요청을 할 때마다 Refresh Token도 재발급 받는 Refresh Token Rotation 방식을 사용한다.
Refresh 토큰 또한 만료 기간이 단축되기 때문에 위험을 줄일 수 있다.
3. 토큰 블랙리스트
- 토큰 유효 기간이 만료되면 Redis 같은 인메모리 DB에 저장해 해당 토큰을 이용한 인증 요청을 거부하도록 하는 방식이다.
- 인메모리 데이터베이스: 메모리에 데이터를 저장, 관리하는 DB로 휘발성(전원이 꺼지면 데이터 휘발)과
빠른 데이터 접근 속도라는 장점을 갖는다.
1) 인증기간 만료 시 Redis에 토큰 고유 식별자를 키로 토큰을 저장한다.
- TTL 특성을 활용해 일정 시간 후 자동 삭제되도록 한다.
2) 요청 마다 해당 토큰이 블랙리스트에 존재하는지 확인한다.
- 존재 시 요청을 거부한다.
'CS > Network' 카테고리의 다른 글
Servlet (1) | 2025.05.07 |
---|---|
Web Server, WAS (1) | 2025.05.06 |
HTTP API 설계: RESTful API, Maturity Model (0) | 2025.05.06 |
HTTP (1) | 2025.05.06 |
프로토콜과 계층 구조(OSI 7계층 모델) (0) | 2025.05.05 |