본문 바로가기
자습

JWT in the modern web

by litaro 2019. 11. 22.

https://medium.com/swlh/why-do-we-need-the-json-web-token-jwt-in-the-modern-web-8490a7284482

 

Why do we need the JSON Web Token (JWT) in the modern web?

Hold on tight: the HTTP protocol is terribly flawed and when it comes to user authentication this problem screams loudly.

medium.com

HTTP protocol is terribly flawed ? 로 시작하는 블로그로 왜 JWT가 필요한지에 대해 설명한다.

Once upon a time

A problem of state

The HTTP protocol is stateless : REST API를 호출할때마다 서버 입장에서는 매호출이 새롭다. 즉, 이전에 어떤 요청이 있었는지모른다.

https://medium.com/swlh/why-do-we-need-the-json-web-token-jwt-in-the-modern-web-8490a7284482

결국 그림과 같이 get /orders 로 주문 리스트 조회하고 이때 user name과 password로 로그인을 완료한 뒤,

특정 주문 정보를 보고 싶어 get /order/42 를 호출하면 또 user name과 password로 로그인해야한다.

이를 해결하기 위해... The traditional way of dealing with this is the use of Server Side Sessions (SSS)

https://medium.com/swlh/why-do-we-need-the-json-web-token-jwt-in-the-modern-web-8490a7284482

Server에서 session ID를 발급해서 해당 ID를 서버는 메모리에 들고 있어서 요청이 들어오면 매번 DB를 찾을 필요는 없어지게 된다.

A problem of scale

위 기술도.. 예전에는 common 했지만 오늘날에는.. outdated 기술이다.

In the API era, our endpoints can face a huge amount of requests, so our infrastructures needs to scale.

스케일 방법은 크게 두가지..vertical scaling (서버 자체 Resource 추가해서 성능 높이는 방법) , horizontal scaling (Load Balanace 뒤에 서버를 여러대 추가하는것).. 심플하고 효율적인 방법은 horizontal scaling

https://medium.com/swlh/why-do-we-need-the-json-web-token-jwt-in-the-modern-web-8490a7284482

서버 한대만 있다면 메모리에 들고 있는게 OK

https://medium.com/swlh/why-do-we-need-the-json-web-token-jwt-in-the-modern-web-8490a7284482

하지만 서버를 한대 추가하면.. 별도의 서버라 메모리에 다른 서버에서 들고 있던 session ID가 없다.

방법은

  • Synchronize sessions between servers: 이건 좀.. 에러 발생 가능성도 있고
  • Use an external in-memory database : 좋은 방법 이지만 infra 추가되는것..

그래서 나온것이..JWT

The better solution

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a way for transmitting information –like authentication and authorization facts– between two parties: an issuer and an audience. 

핵심은 Token 자체가  authentication, authorization 에 필요한 모든 정보를 들고 있다. self-contained

stateless HTTP 속성에 맞게 각 Request의 Token에 모든 정보 있으면 문제가 없어진다.

그리고 디지털 서명화되어 있어 변조되지 않음을 보장할수 있다.

Anatomy of a JWT

header.payload.signature

세 가지 part 정보로 이루어진다. 

Header

Token 에 대한 정보를 가지고 있다. 아래 정보가 담긴 JSON을 Base64URL 로 encode 한 String

{
  "kid": "ywdoAL4WL...rV4InvRo=",
  "alg": "RS256"
}
  • kid : 해당 token을 validate 할때 쓰이는 key
  • alg : 해당 token을 sign 할때 쓰이는 알고리즘

Payload or body

contains information (claims in JWT jargon) about the client. 이 정보를 Base64URL로 encoding한 string

{
  [...]
  "iss": "https://cognito-idp.eu-west-1.amazonaws.com/XXX",
  "name": "Mariano Calandra",
  "admin": false
}
  • iss: registered claim 으로 token을 발행한 주체
  • admin: 서비스에서 필요하여 추가한 claim (비공개 clame)

Signature

아래 Step을 따라 hash 된 String

  • encoded Header + "." + encoded Payload 를 합쳐서
  • Header에서 정의된 alg 값의 알고리즘으로 private key로 hash하여
  • Base64URL로 encode

위와 결과로 만들어진 Token을 아래와 같은 형태로.. 이게 제대로 되었는지는 https://jwt.io 사이트의 Debugger에서 확인 가능

주의사항: 암호화된 것처럼 보이지만, Base64URL은 암호화가 아니다.

https://jwt.io

JWT validation

validation을 위해 필요한것은 public key. public key를 어떻게 가져오는지 알아보자

(비대칭 암호화 방식은 pubic key로 encrypt하고 private key로 decrypt하는데 signing 알고리즘은 반대로 private key로 sign하고 public key로 vafiry함)

Amazon Cognito의 경우 body의 'iss' 값 (issuer 의 endpoint) 에 /.well-known/jwks.json 을 붙이면 아래와 같다.

해당 URL로 부터 아래 정보를 얻어온다.

token header의 'kid' 를 위의 keys array에서 찾은 'e'와 'n'의 정보로 public key 계산한다.

상세한 것은 범위를 벗어나므로... 

A real case scenario

위와 같은 그림에서 JWT를 사용함으로써 API 서버는 5번..JWT token만 validate한지 보면 된다.

그리고 권한에 대해서는 ... 만약 DELETE /order/42 는 admin 권한이 있는 사람에게만 주고 싶다..하면 custom claim

Summary

  • HTTP protocol은 stateless하기 때문에 각 요청이 새로워 이전 정보를 모른다.
  • Server Side Sessions 이 한때 위 이슈의 해결책이었으나 scaling 이슈로 요즘에는 안쓰인다.
  • JWT 은 self-contained 라서 자체 적으로 요청에 대해 allow/deny 정보를 가지고 있다.
  • JWT Design 부터 stateless 하기 때문에 HTTP stateless 이슈에 적절한 해결책이다.
  • JWT 은 encoded 지 encrypted 는 아니다.