JWT(Json Web Token)에 대해 알아보려 합니다.
이 글에서는 공식문서의 내용을 기반으로 제 경험을 섞을 것입니다.
JWT란?
JSON Web Token은 JSON 객체로 정보를 안전하게 전송하는 자체적인 방법을 정의한 표준입니다.
이 정보들은 디지털 서명이 되어있으므로 신뢰할 수 있습니다.
비밀키나 RSA 혹은 ECDSA를 사용한 공개/개인키를 사용하여 JWT는 서명되어 질수 있습니다.
JWT를 사용하는 경우?
- 인증 : JWT를 쓰는 가장 흔한 경우입니다.
사용자가 로그인을 하면 이후의 연속된 요청들은 JWT를 포함하게 되고(헤더에 포함됨), user에게 routing, service 이용, 자원에 대한 접근을 허용합니다.
jwt는 작은 overhead를 유발하고 다른 도메인간에 쉽게 사용될수 있기 때문에 요즈음 널리 쓰입니다. - 정보 교환 : 당사자간에 안전하게 정보를 교환하기 위해 JWT는 좋은 방법입니다. JWT는 서명되어 질수 있고 그들이 누구인지 요청자를 확인할수 있기 때문입니다. 또한 서명은 header와 payload를 사용하여 계산되므로 내용이 변조 되지는 않았는지 확인할 수 있습니다.
JWT의 구조
- Header
- Payload
- Signature
위의 세가지 요소는 dot(.)으로 구분이 됩니다.
xxxx.yyyy.zzzz
Header
보통 토큰의 종류와 사용된 알고리즘에 대한 명시로 구성됩니다. (이떄 토큰의 종류는 JWT)
{
"alg": "HS256",
"typ": "JWT"
}
header의 json은 Base64Url로 인코딩 되어 JWT의 첫번째 부분에 위치하게 됩니다.
Payload
claim을 포함하고 있는 두번째 부분입니다. 클레임은 사용자에 대한 정보나 추가 정보를 가지고 있는 statements 입니다.
세가지 타입이 있는데 registered, public, private claim이 있습니다.
- Registered claims : 사전에 정의되어 있는 claim 입니다. 필수 사항은 아니고 권장 사항 입니다.
iss(issuer), exp(expiration time), sub(subject), aud(audience)와 같은 것들이 있습니다. - Public claims : jwt를 사용하는 사용자가 자유롭게 정의할 수 있습니다. 충돌을 방지하기 위해 JSON 웹 토큰 레지스트리에 정의하거나 충돌 방지 네임스페이스를 포함하는 URI로 정의해야 합니다(URI정의 방식은 잘 모르겠습니다)
- Private claims : 당사자간에 정보를 공유하기 위한 커스텀 claim 입니다.
payload의 예시
{
"sub": "12345678",
"name": "John Doe",
"admin": true
}
위 정보들은 Base64Url 방식으로 인코딩 되어 JWT의 두번째 부분을 구성합니다.
Signature
서명부분을 생성하기 위해서는 인코딩된 header, 인코딩된 payload, 비밀키, 헤더에 명시된 알고리즘을 가져와 서명해야 합니다.
만약에 HMAC SHA256 알고리즘을 사용하길 원한다면 서명은 아래의 방식으로 만들어 집니다.
HMACSHA256(
base64UrlEncode(header) + "." +
base64UrlEncode(payload),
secret)
이 서명은 메시지가 전송 과정에 변경되지 않았는지 확인하는데 사용이 됩니다. 그리고 토큰을 개인키와 같이 서명한 경우에는 JWT를 보낸 사람이 누구인지도 확인할 수 있습니다.
JWT 동작 방식
인증에서 유저가 로그인을 성공하면 JWT가 반환됩니다. 토큰에는 민감한 정보가 들어갈 수 있기 때문에 주의해야 합니다.
유저가 리소스나 route에 접근 하길 원할때 user agent는 Authorization 헤더에 Bearer <token> 형식으로 보내야 합니다.
Authorization: Bearer <token>
요청이 들어오면 서버에서는 Authorization 헤더의 JWT를 검사하고 권한을 가지고 있는지를 체크 합니다. JWT가 필요한 데이터를 가지고 있다면 데이터베이스를 거치지 않아도 되므로 효율적일 수 있습니다.
HTTP로 보낼때는 사이즈가 너무 커지지 않도록 주의해야 합니다. 몇몇 서버에는 헤더의 크기에 제한이 있습니다. nginx를 이용하여 서비스를 구성했었는데 nginx의 JWT의 사이즈를 너무 크게 잡아 nginx의 header size limit을 넘어버려서 에러를 경험한 기억이 있습니다.
토큰이 Authorization 헤더에서 보내진다면 CORS에서 issue는 발생하지 않을 겁니다.
CORS에서 setCookie를 하기 위해선 Access-Control-Allow-Credentials를 true로 주고 Access-Control-Allow-Origin에는 무조건 같은 도메인만 있어야 합니다. 이때는 *(wildcard)를 사용할 수 없습니다
JWT를 왜 써야 할까요?
JWT말고도 SWT(Simple Web Tokens), SAML(Security Assertion Markup Language Tokens)와 같은것들도 있습니다.
json은 xml보다 사이즈가 작습니다. HTML과 HTTP 환경에서는 같은 정보를 더 작은 크기로 보낼수 있게 해줍니다.
json parser는 바로 객체를 가리키기 때문에 대부분의 언어에서 흔합니다. xml은 자연스러운 document-to-object mapping을 가지고 있지 않습니다.
출처: https://jwt.io/introduction
'네트워크' 카테고리의 다른 글
네트워크 Browser 요청의 제한🌱 (HTTP/1.1, HTTP/2) (0) | 2022.04.21 |
---|---|
주소창에 www.google.com을 입력하면?(성공과 실패를 결정하는 1% 네트워크 원리) (0) | 2022.04.17 |
네트워크 HTTP, HTTPS, SSL HandShake 😶🌫️ (0) | 2022.04.17 |
네트워크 HTTP, HTTP 1.1, HTTP 2.0 🔥 (0) | 2022.04.16 |
html5, 웹 표준 및 웹 접근성 🔥 (0) | 2022.04.13 |