✅ JWT란
JWT(JSON Web Token)의 약자로, Json 포맷을 이용해 인증에 필요한 정보를 암호화 한 웹 토큰이다. JWT는 아래 사진 같이 긴 암호화 된 토큰으로, 토큰 자체를 정보로 사용하는 Self-Contained 방식으로 안전성을 보장한다. 주로 회원 인증이나 정보 전달을 위해 쓰이며, Access Token(JWT)을 HTTP 헤더에 넣어 서버와 통신한다.
✅ JWT 구조
JWT 공식 사이트에 들어가면 암호화된 토큰을 볼 수 있다. 위에 사진을 보면 토큰이 세 가지 색깔로 구분이 되어있다. 자세히 보면 빨강, 분홍, 하늘 색깔 사이에 온점이 있는데, 이 온점이 바로 토큰을 구성하는 세 가지 요소를 구분하는 기준이다.
토큰을 만들기 위해서는 세 가지 요소 "Header, Payload, Verify Signature"가 필요하다.
header + "." + payload + "." + signature
Header: 토큰 타입, 암호화 알고리즘 지정
Payload: 서버에서 보내는 데이터, 토큰에서 사용할 정보의 조각들인 '클레임'이 담겨있음
Signature: 토큰을 인코딩하거나 유효성 검증을 할 때 사용하는 고유한 암호화 코드
따라서 일반적으로 JWT는 아래와 같은 구조를 띈다.
xxxxx.yyyyy.zzzzz
1. Header (헤더)
JWT 토큰의 헤더는 typ와 alg 두 가지 정보로 구성된다. alg는 signature를 암호화 할 알고리즘 방식을 지정하고, typ는 토큰의 타입을 지정한다.
- alg: 암호화 알고리즘 방식을 지정한다. 서명(Signature)을 암호화 하거나, 토큰 검증에 사용된다. (ex. HS256, RSA)
- typ: 토큰의 타입을 지정한다. (ex. JWT)
{
"alg": "HS256",
"typ": "JWT"
}
2. Payload (페이로드)
Payload에는 토큰에 담을 정보가 들어간다. Payload에 담는 정보의 한 조각을 클레임(claim) 이라고 부르며, 토큰에는 여러개의 클레임을 넣을 수 있다. 클레임은 총 세 가지로 나뉘며 Json(Key/Value) 형태로 다수의 정보를 넣을 수 있다.
- 등록된 클레임(Registered Claim)
등록된 클레임들은 이름이 이미 정해져있는 클레임으로 토큰에 대한 정보들을 담기 위해 사용된다. (사용자가 정한 이름이 아님) 등록된 클레임은 선택적으로 사용할 수 있으며, JWT를 간결하게 하기 위해 key는 모두 세 문자열로 이뤄져 있다.
iss: 토큰 발급자 (issuer)
sub: 토큰 제목 (subject). subject로는 unique한 값을 사용하는데, 사용자 이메일을 주로 사용함.
aud: 토큰 대상자 (audience)
exp: 토큰 만료시간 (expiraton), NumericDate 형식. (예: 1480849147370) 현재 시간 이후로 설정되야 함.
nbf: 토큰 활성 날짜 (not before). NumericDate 형식. 해당 날짜가 지나기 전까지는 토큰 비활성화
iat: 토큰 발급 시간 (issued at). 토큰 발급 이후 경과된 시간을 알 수 있음.
jti: JWT 토큰 식별자(JWT ID). 중복 처리를 방지하기 위해 사용. 일회용 토큰(Access Token)등에 사용하면 유용.
- 공개 클레임(Public Claim)
공개 클레임은 사용자 정의 클레임으로, 공개용 정보를 위해 사용된다. 충돌 방지 (collision-resistant) 를 위해 클레임 이름을 URI 포맷으로 적는다.
{
"https://uiop5809.tistory.com/": true
}
- 비공개 클레임(Private Claim)
비공개 클레임은 사용자 정의 클레임으로, 클라이언트와 서버간 협의하에 사용되는 클레임 이름들이다. 공개 클레임과는 달리 이름이 중복되어 충돌이 될 수 있으니 사용할때에 유의해야한다.
{
"username": "pyj"
}
payload
{
// 등록된 클레임
"sub": "23442s5b-1adf-4sff-sdf939-6sdf0c0b91f7", // 토큰 제목
"iss": "https://cognito-idp.ap-northeast-2.amazonaws.com/ap-northeast-2_~~", // 토큰 발급자
"iat": 1925144429, // 토큰이 발급된 시간
"exp": 1925148029, // 토큰의 만료 시간
"jti": "89adf5-e434-w20d-3432f-456c4adf73", // JWT의 고유 식별자
// 공개 클레임
"https://uiop5809.tistory.com/": true,
// 비공개 클레임
"username": "pyj"
"event_id": "893a4c1b-3d67-4b8d-a57f-4ed8bcf90c6c",
"token_use": "access",
"scope": "aws.cognito.signin.user.admin",
"auth_time": 1625144429,
"client_id": "79307ehbtr2o3ln1ip8dcb9v6p",
}
3. Signature (서명)
서명(Signature)은 토큰을 인코딩하거나 유효성 검증을 할 때 사용하는 고유한 암호화 코드이다.
Signature은 헤더(Header)와 페이로드(Payload)의 값을 각각 BASE64로 인코딩하고, 인코딩한 값을 비밀키로 해싱을 하여, 이 값을 다시 BASE64로 인코딩하여 생성한다. 이때 비밀키로 해싱하는 알고리즘은 (Header)에서 정의한 알고리즘을 사용한다. 비대칭 키 방식인 RS256(RSA Sinature with SHA-256)와 대칭키 방식인 HS256(HMAC with SHA-256)를 주로 사용한다.
✅ JWT 토큰 사용
생성된 JWT 토큰은 HTTP 통신을 할 때 헤더에 넣어서 사용한다. 헤더에 넣을 때 Authorization이라는 key의 value로 사용되며, 일반적으로 Bearer라는 문자열이 앞에 붙여진다.
{
"Authorization": "Bearer {JWT token 값}"
}
✅ JWT 토큰 사용시 주의사항
최종적으로 JWT 토큰은 Encoded Header + "." + Encoded Payload + "." + Verify Signature 형태를 띄게 된다. 이때, Header, Payload는 인코딩 될 뿐(16진수로 변경), 따로 암호화되지 않는다. JWT 토큰에서 Header, Payload는 누구나 디코딩하여 확인할 수 있기 때문에 비밀번호와 같은 중요한 정보는 넣지 말아야 한다.
다행히도, Verify Signature는 secret_key를 알지 못하면 복호화할 수 없다. 즉, B라는 해커가 A의 정보가 든 payload를 조작해서 인코딩 후 서버에 보내더라도, Verify Signature는 A의 Payload를 기반으로 암호화되었기 때문에 유효하지 않는 토큰으로 간주한다. 즉, secret_key를 알지 못하면 토큰을 조작할 수는 없다.
'🍞 Front-End > React' 카테고리의 다른 글
[React] 간단한 토글 메뉴 구현하기 (0) | 2022.11.21 |
---|---|
[React] 리액트 프로젝트에 구글 폰트 적용하기 (0) | 2022.11.18 |
[Recoil] Recoil 상태관리 라이브러리 (0) | 2022.11.02 |
[React] Uncaught TypeError index.js (0) | 2022.11.02 |
[MSW] 데이터 모킹 라이브러리 (Mock Service Worker) (0) | 2022.11.01 |