시작으로
최근 Express.js
로 사내 rest-api서버를 구축했었는데, 그 중 사용자 인증을 처리를 JWT로 구현했었다.
그때는 사용방법만 빠르게 익히고 구현했기 때문에 정리할 시간이 없었다.
현재 서비스를 오픈하고 시간이 남아서 지금이라도 정리를 해본다.(기억 < 기록 )
본 포스트는 JWT 공식문서를 번역 및 테스트하여 정리한 글이다.
JSON 웹 토큰이란?
JWT(JSON Web Token)
는 당사자 간에 정보를 JSON
개체로 안전하게 전송하기 위한 간결하고 자체 포함된 방법을 정의하는 개방형 표준이다. 이 정보는 디지털 서명이 되어 있으므로 신뢰할 수 있다.
JWT
는 비밀(HMAC
알고리즘 사용)을 사용하거나 RSA
또는 ECDSA
를 사용하는 공개/개인 키 쌍을 사용하여 서명할 수 있다.
JSON 웹 토큰은 언제 사용하는가?
-
인증(Authorization)
, 가장 일반적으로 사용하는 이유이다. 사용자가 로그인하면 서버에서 토큰을 발급해주고 후속 요청에는 JWT가 표함되어 사용자가 해당 토큰으로 허용되는 경로, 서비스 및 리소스에 엑세스할 수 있다. -
정보 교환
, 당사자 간에 정보를 안전하게 전송하는 좋은 방법이다. 공개/개인 키 쌍을 사용하여 JWT에 서명할 수 있기 때문에 발신자가 누군지 확인할 수 있다. 또한, 헤더와 페이로드를 사용하여 서명을 계산하므로 콘텐츠가 변조되지 않았는지 확인할 수 있다.
JSON 웹 토큰의 구조
간결한 형태의 JSON 웹 토큰은 점(.)
으로 구분된 세 부분으로 구성되어 있다.
- 헤더, Header
- 페이로드, Payload
- 서명, Signature
따라서, JWT는 일반적으로 아래와 같다.
xxxxx.yyyyy.zzzzz
Header
Header는 일반적으로 JWT인 토큰 유형과 HMAC SHA256
또는 RSA
와 같이 사용 중인 서명 알고리즘의 두 부분으로 구성되어있다.
{
"alg": "HS256",
"typ": "JWT"
}
그 다음, 이 JSON은 JWT의 첫 번째 부분을 형성하도록 인코딩된 Base64Url
이다.
Payload
JWT의 두 번째 부분은 클레임(Claims)
을 포함한 Payload
이다. 클레임(Claims)
은 엔티티 및 추가 데이터에 대한 설명이다.
클레임(Claims)
에는 registered
, public
, and private claims
3가지 유형이 있다.
-
등록된 클레임(Registered claims) : 필수는 아니지만, 유용하고 상호 운용 가능한 클레임 집합을 제공하기 위해 권장되는 미리 정의된 클레입 집합이다. 그 중 일부는
iss(발급자)
,exp(만료 기간)
,sub(제목)
,aud(대상)
및 기타이다. -
공개 클레임(Public claims) : JWT를 사용하는 사람들이 마음대로 정의할 수 있다. 그러나 충돌을 방지하려면 IANA JSON Web Token Registry에서 정의하거나 충돌을 방지할 수 있는 네임스페이스를 포함하는 URI로 정의해야 한다.
-
비공개 클레임(Private claims) : 사용에 동의하고 등록된 클레임이나 공개 클레임이 아닌 당사자간에 정보를 공유하기 위해 생성된 맞춤 클레임이다.
{
"sub": "1234567890",
"name": "John Doe",
"admin": true
}
그 다음, Payload는 Base64Url
로 인코딩되어 JWT의 두 번째 부분을 형성한다.
서명된 토큰의 경우 이 정보는 변조로부터 보호되지만 누구나 읽을 수 있다. 암호화되지 않은 경우 JWT의 Payload 또는 header 요소에 비밀 정보를 넣지 말아야된다.
Signature
서명을 생성하려면 인코딩된 header
, 인코딩된 Payload
, secret
, header에 지정된 알고리즘을 가져와서 서명해야 한다.
예를 들어 HMAC SHA256 알고리즘을 사용하려는 경우 서명은 다음과 같이 생성된다.
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
서명은 메시지가 도중에 변경되지 않았는지 확인하는 데 사용되며 개인 키로 서명된 토큰의 경우 JWT의 보낸 사람이 누군지 확인할 수도 있다.
모두 합치면
출력은 HTML 및 HTTP 환경에서 쉽게 전달할 수 있도록 점으로 구분된 3개의 Base64-URL 문자열이다.
다음은 header와 payload가 인코딩되어 있고 비밀로 서명된 JWT를 보여준 것이다.
JWT를 사용하고 이러한 개념을 실제로 적용하고 싶다면 jwt.io 디버거 를 사용하여 JWT 를 디코딩, 확인 및 생성할 수 있다.
JSON 웹 토큰은 어떻게 작동하는가?
- 인증에서 사용자가 자격 증명을 사용하여 성공적으로 로그인하면 토큰을 생성하여 반환한다.
- 일반적으로 토큰을 필요 이상으로 오래 보관하지 않는다.
- 또한, 보안이 취약하기 때문에 민감한 세션 데이터를 브라우저 저장소에 저장해서는 안된다.
- 사용자가 보호된 경로 또는 리소스에 엑세스하려고 할 때마다 사용자는
Bearer
스키마를 사용하여 HTTP 헤더에Authorization
를 탑재하여 JWT를 보내야 한다. - HTTP 헤더를 통해 JWT 토큰을 보내는 경우 토큰이 너무 커지지 않도록 해야 한다. 일부 서버는
8KB
이상의 헤더를 허용하지 않는다. - 토큰이
Authorization
헤더로 전송되면CORS(Cross-Origin Resource Sharing)
는 쿠키를 사용하지 않으므로 문제가 되지 않는다.
Authorization: Bearer <token>