JWT(Json Web Token)
인터넷 표준 인증 방식
인증에 필요한 정보들을 Token
에 담아 암호화 시켜 사용하는 것
일반적으로 쿠키 저장소
를 사용하여 JWT를 저장한다
필요한 모든 정보를 한 객체에 담아서 전달
하기 때문에 JWT 한 가지로 인증을 마칠 수 있다
JWT는 서명된 토큰
공개/개인 키를 쌍으로 사용하여 토큰에 서명할 경우 서명된 토큰은 개인 키를 보유한 서버가 서명된 토큰이 정상적인 토큰인지 인증
할 수 있다
JWT의 구조 때문에 인증 정보를 담아 안전하게 인증
을 시도하게끔 전달할 수 있다
공식 사이트 : https://jwt.io/
JWT를 사용하는 가장 일반적인 경우
사용자가 로그인을 하면 각 후속 요청에 JWT가 포함되어 사용자가 해당 토큰으로 허용되는 경로, 서비스 및 리소스에 엑세스 할 수 있다
JWT는 당사자 간에 정보를 안전하게 전송할 수 있는 방법
중 하나
-Session 로그인 기능을 사용할 경우, Session storage가 모든 Client의 로그인 정보를 소유하고 있기 때문에 모든 서버에서 Session storage
를 방문하여 API 요청을 처리해야 한다.
하지만, JWT를 사용한다면 로그인 정보를 Server에 저장하지 않고 Client에 로그인 정보를 JWT로 암호화하여 저장하기 때문에 JWT를 통해 인증과 인가 과정을 진행시킬 수 있다
모든 서버에서는 동일한 Secret Key
를 소유하고, 이 Secret Key를 통해 암호화와 위조 검증이 가능하다
(Secret Key)에 대한 내용은 나중에 더 다루어볼 생각이다
HEADER
. PAYLOAD
. SIGNATURE
위와 같이 헤더, 내용, 서명이 .(dot)
을 구분자로 하여 JWT 토큰 1개를 이룬다
완성된 토큰은 다음과 같은 형태를 가진다
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
ALGORITHM & TOKEN TYPE
Header에는 보통 토큰의 타입과, 서명을 생성할 때 어떤 알고리즘이 사용되었는지 저장한다
{
"alg": "HS256",
"typ": "JWT"
}
위와 같은 경우는, 현재의 토큰 타입이 JWT
이고, 서명을 생성할 때 HS256
알고리즘이 적용되어 암호화가 되어 있음을 나타낸다
DATA
Payload에는 Claim을 포함한다. 클레임은 Entity(일반적으로 사용자) 및 추가 데이터에 대한 설명이다. 클레임에는 등록된 클레임, 공개 클레임, 비공개 클레임 세 가지의 유형이 있다.
유용하고 상호 운용 가능한 클레임 집합을 제공하기 위해 필수는 아니지만 권장되는
미리 정의된 클레임 집합이다.
그 중에는 iss (발행자), exp (만료 시간), sub (토큰 제목), aud (토큰 대상자) 등이 있다.
표준 스펙 상 key의 이름은 3글자로 되어 있다.
JWT의 핵심 목표는 사용자에 대한, 토큰에 대한 표현을 압축하는 것이기 때문에 이를 정의한 것이라고 볼 수 있다.
JWT를 사용하는 사람들이 원하는 대로 정의할 수 있다.
그러나 충돌을 방지하려면 IANA JSON 웹 토큰 레지스트리
에 정의하거나 충돌 방지 네임 스페이스
를 포함하는 URI로 정의해야 한다
사용에 동의한 당사자 간에 정보를 공유하기 위해 생성된 맞춤 클레임
으로, 등록되거나 공개된 클레임이 아니다
Payload의 예시
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
위 Payload에서는 토큰의 제목과 대상자의 이름, 그리고 토큰 발급 시간을 나타낸다
Payload에 민감한 정보를 담지 않는 것!
header와 payload는 json이 인코딩 되어 있을 뿐, 특별한 암호화가 걸려 있는 것이 아니기 때문에 누구나 jwt를 가지고 디코딩을 하면 그 값을 알 수 있다
JWT는 단순하게 "식별을 하기 위한" 정보만을 담아두어야 한다
VERIFY SIGNATURE
가장 중요한 서명!
서명 부분을 생성하려면 인코딩된 헤더, 인코딩된 페이로드, secret key, 헤더에 지정된 알고리즘 을 가져와서 서명해야 한다
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
[your-256-bit-secret]
)
위는 HMAC SHA256 알고리즘을 사용해서 서명을 생성하려는 경우이다
서명은 메시지가 도중에 변경되지 않았는지 확인하는 데 사용되며, 개인 키로 서명된 토큰의 경우 JWT를 보낸 사람이 누구인지도 확인할 수 있다
Authorization : Bearer <Token>
Authorization
, JWT가 있으면 사용자는 보호된 리소스에 엑세스할 수 있다다음 다이어그램은 API 또는 리소스에 엑세스하기 위해 JWT를 획득하고 사용하는 방법을 보여 준다
1. 애플리케이션이나 클라이언트가 인증 서버에 인증을 요청
2. 권한이 부여되면 권한 서버는 애플리케이션에 엑세스 토큰을 반환
3. 애플리케이션은 엑세스 토큰을 사용하여 보호된 리소스(예 : API)에 엑세스
HTTP 헤더를 통해 JWT 토큰을 보내는 경우 토큰이 너무 커지지 않도록 해야 한다
토큰이 Authorization
헤더로 전송되면 CORS(Cross-Origin Resource Sharing)는 쿠키를 사용하지 않으므로 문제가 되지 않는다