1. Cookie vs Session vs JWT
Http의 가장 큰 특징은 비연결성, 무상태성이다. 즉, 한번 요청과 응답을 통하면 똑같은 일을 하기 위해서라도 동일한 정보를 전송하고 받아야 한다는 말이다. 이를 보완하기 위해 나온 기술이 Cookie와 Session이다.
이 장에서는 아주 핵심만 간략하게 설명하겠다.
Cookie
웹사이트 접속시 접속자의 개인장치에 다운로드 되고 브라우저에 저장되는 작은 텍스트 파일. key - value형태.
장점 : client측에서 데이터를 저장 => server부담 없음
단점 : client에서 마음데로 조작이 가능. 용량이 작음
Session
일정시간동안 같은 사용자(정확하게 브라우저를 말한다)로 부터 들어오는일련의 요구를 하나의 상태로 보고 그 상태를 일정하게 유지시키는 기술
장점 : server측에 데이터를 저장 => JSESSIONID가 server에 저장되어 안전.
단점 : server에 과부하가 생길 수 있음. 그러므로 필수적인 데이터만 저장해야 한다.
쿠키는 너무 나약(?)하고... 그렇다고 Session만 쓰기에는 좀 무겁고... 아니 둘의 중간은 없을까...?
하면서 나온것이 JWT다.
참고 : https://medium.com/swlh/why-do-we-need-the-json-web-token-jwt-in-the-modern-web-8490a7284482
2. 그래서 JWT? 넌 뭐니?
JWT에 대한 내용은 아주 쉽게 찾을 수 있다. 하지만 필자는 jwt.io에서 이 내용을 찾아보고자 했다.
궁금한 분은 밑의 사이트에서 읽기를 추천한다.
출처 : https://jwt.io/introduction
What is JSON Web Token?
JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.
Json Web Token(JWT)는 JSON 객체 부분들 사이에 안전하게 정보를 전송하는 컴팩트하고 self-contained way한 오픈 스탠더드다. 즉 안전하게 정보를 전송하기 위한 하나의 방식인 것이다.
3. 왜 써야 하니?
결국 필요에 의해서 나온 것이 JWT이다. Cookie와 Session에 대해 설명할 때 보았듯이 cookie에도 적당히 데이터를 넣고, 너무 무겁지도 않은 암호화된 데이터를 필요로 하는 목적에서 JWT가 탄생한 것이다.
이를 이용해서 얻을 수 있는 이점이 무엇인지 찾아봤다.
이점
Authorization
jwt를 쓰는 가장 흔한 방법. 유저가 로그인 하면, 각각 연속적인 요청이 유저가 route, service, 혹은 resources에 접근을 허가하는지에 대한 정보를 jwt를 포함합니다. single sign on 은 작은 오버헤드와 다른 도메인에서도 쉽게 사용할 수 있는 능력 때문에 JWT를 요즘 널리 쓰는 특징입니다.
* 오버헤드(overhead)는 어떤 처리를 하기 위해 들어가는 간접적인 처리 시간 · 메모리 등을 말한다.
Information Exchange
Jwt는 안전하게 party들 사이에 정보를 전달하기위한 좋은 방법입니다. 공개/비공개키를 이용해 JWT는 sign될 수 있고, 당신은 송신자가 누구인지 확실히 할 수 있습니다. 추가적으로, 서명이 헤더와 페이로드를 이용하는데 계산할 때, 내용물이 함부로 변경되지 않음을 증명할 수 있습니다.
단점
Payload 정보가 많아지면 네트워크 사용량 증가, 데이터 설계 고려 필요
토큰이 클라이언트에 저장 => 서버에서 토큰 조작 못함.
4. JWT의 구조
JWT는 3개로 나뉜다.(곤충인줄... 머리, 가슴, 배...)
- Header
- Payload
- Signature
이것을 순서대로 합쳐서 한줄로 보내면 다음과 같은 형식이 된다.
xxxxx.yyyyy.zzzzz
헤더(Header)
signing 알고리즘에 사용된 암호화 형식과 타입이 담겨있다.
- example -
{
"alg":"HS256",
"typ":"JWT"
}
페이로드(payload)
claims를 포함한다. claims란 entity와 추가적인 데이터에 대한 상태다. claims에는 다시 3개의 종류가 있다.
- registered claims : 의무적이진 않지만 추천되는 미리 정의된 claims의 세트다.
- public cliams : jwt를 사용하면서 마음대로 정의될 수 있다. 하지만 collision을 피하기 위해 IANA Json Web Token Registry 혹은 collision resistant namespace인 uri로 정의되어야 한다.
- private claimns : registered claims 혹은 public cliams가 아닌 것들의 사용을 허가하기 위한, party들 사이에 정보를 공유하기 위해 생성된 custom claims들이다.
- example -
{
"sub":"1234567890",
"name":"John Doe",
"admin":true
}
Signature
signature 부분을 만들려면 암호화된 header, 암호화된 payload, 시크릿, 헤더에서 특화된 알고리즘을 가져와야만 한다.
예를 들어, JMAC SHA256 알고리즘을 사용하고 싶으면, signature는 다음과 같은 방식으로 만들어질 것이다.
HMACSHA256(
base64UrlEncode(header) +"."
+ base64UrlEncode(payload), secret)
signature는 메시지가 그 과정에서 변하지 않았는지 증명하기 위해 사용된다. 비공개 키에서 signed된 토큰들의 경우에, jwt의 전송자가 누구인지 또한 알 수 있다.
Putting all together - 모두를 한번에!
출력은 HTML과 HTTP 환경에서 쉽게 통과 가능한 .(dot)으로 구분된 세개의 Base64-URL 스트링이다.
SAML같은 XML 기반과 비교될 때 더 컴팩트하다.
우리가 위에서 본 구조는 decoded된 것이고, .으로 구성된 것을 잘라서 사용한 알고리즘으로 다시 만들어보면 위의 구조 형식으 나올 것이다.
5. JWT는 어떻게 작동하나?
그러면 이 JWT가 어떻게 작동하는지 알아보자.
인증에서 유저가 성공적으로 로그인 하면, JWT가 반환될 것이다.
토큰은 credentials이 있기 때문에, greate care가 보안 이슈를 해결하기 위해 필수적이다. 일반적으로, 요구되는 것 보다 토큰을 길게 가지고 있어서는 안된다. => 일정 시간이 지나면 파기!
그리고 보안의 취약성 때문에 브라우저 저장소에 민감한 session data을 가지고 있어서는 안된다.
사용자가 보호된 route 혹은 resource에 접근할 때 마다 유저 agent는 jwt를 보내야한다. 전형적으로 bearer schema 를 사용한 인증 헤더에서 말이다. 헤더의 내용물은 다음과 같다.
Authroization: Bearer <token>
이것은 특별한 경우에 무상태성 인증 메커니즘일 수 있다. 서버의 보호된 루트는 인증 헤더에서 valid한 jwt를 확인할 것이다. 만약 존재한다면, 유저는 보호된 리소스들에 접근할 수 있다. 만약 jwt가 필요한 데이터를 포함한다면, 특정 작동을 위해 database query를 만들 필요가 줄어들 것이다! 늘 그런건 아니지만!
=> 마지막에 중요한 말이 있다. 인증을 할 때 마다 db에 접근하는 것이 아니라, 어느정도 선에서 db에 접근하는 불필요한 작업이 필요없이 jwt로 구현이 가능하다는 말이다.
토큰이 인증 헤더에 보내지면, CORS 이슈가 발생하지 않을 것이다.
=> 여기서 뼈아픈 경험이 있는데... jwt 는 단순 string기반의 token이기 때문에 데이터를 전송한다는 개념에서 CORS 문제가 생기지 않는다는 것 같다.
The following diagram shows how a JWT is obtained and used to access APIs or resources:
- The application or client requests authorization to the authorization server. This is performed through one of the different authorization flows. For example, a typical OpenID Connect compliant web application will go through the /oauth/authorize endpoint using the authorization code flow.
- When the authorization is granted, the authorization server returns an access token to the application.
- The application uses the access token to access a protected resource (like an API).
이렇게 JWT에 대해서 알아보았다.
모든 내용은 인터넷에서 쉽게 찾을 수 있다.
다만 중요한 것은 이것을 정말 내것으로 만드는 것이다. 필자는 그러기 위해 노력을 했고, 이것을 바탕으로 spring security 에 적용할 예정이다.
'Spring > Spring Security' 카테고리의 다른 글
[Spring Security] 저장 메커니즘(Storage Mechanism) (0) | 2022.07.19 |
---|---|
[Spring Security] Username/password authentication : form / basic (0) | 2022.07.17 |
[Spring Security] 인증(Authentication) & 서블릿 인증 구조(Servlet Authentication Architevture) (2) | 2022.07.17 |
[Spring Security] 구조(Architecture)와 이해 (0) | 2022.07.16 |
[Spring Security] Spring Security란? (feat.학습 이유) (0) | 2022.07.15 |