https://medium.com/swlh/why-do-we-need-the-json-web-token-jwt-in-the-modern-web-8490a7284482
HTTP protocol is terribly flawed ? 로 시작하는 블로그로 왜 JWT가 필요한지에 대해 설명한다.
Once upon a time
A problem of state
The HTTP protocol is stateless : REST API를 호출할때마다 서버 입장에서는 매호출이 새롭다. 즉, 이전에 어떤 요청이 있었는지모른다.
결국 그림과 같이 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)
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
서버 한대만 있다면 메모리에 들고 있는게 OK
하지만 서버를 한대 추가하면.. 별도의 서버라 메모리에 다른 서버에서 들고 있던 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은 암호화가 아니다.
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 는 아니다.
'자습' 카테고리의 다른 글
어떻게 읽을 것인가 (0) | 2020.03.27 |
---|---|
JWT and API Gateway Lambda Authorizer (1) | 2019.11.23 |
How to Host a Static Website with S3, CloudFront and Route53 (0) | 2019.11.08 |
Multithreading VS Multiprocessing in Python (0) | 2019.11.03 |
Flask, Flask-RESTPlus, and Swagger UI (0) | 2019.10.09 |