다시 정리하는 !!!!!
💡 Web의 인증 방식 중 세션의 메모리 문제를 보완할 수 있는 JWT에 대해 알아보자!
노션에서 보기
📌 요약
- JWT란, 인증에 필요한 정보들을 암호시킨 토큰으로 세션 기반 인증 방식의 문제점을 보완하는 기술이다.
세션의 단점
- 세션 기반의 인증 방식을 사용할 때, 중앙 세션 관리 시스템에서 하나의 문제가 시스템 전체로 확산된다는 문제점 존재
- 사용자가 많아짐에 따라 세션 DB와 서버 확장 필요
- 예를 들어, 내가 사용중인 웹사이트의 사용자가 많아져 세션 DB를 A와 B로 나우었다고 가정하면,
- 나에 대한 정보는 세션 A에 저장되어 있었다.
- 따라서 앞으로 해당 웹 페이지에 Request를 보낼 때 세션 A에서만 통신하도록 하는 추가적인 기술이 필요하다.
→ 이러한 단점을 어느 정도 해결할 수 있는 기술이 JWT인 것
JWT란?
🔐 JWT(JSON Web Token)의 개념
- JWT(JSON Web Token)란, 인증에 필요한 정보들을 암호시킨 토큰이다.
- 토큰의 기본 정보, 전달할 정보, 검증되었다는 Signature 정보를 가지고 있다.
- 필요한 모든 정보를 자체적으로 지니고 있다는 점에서, 자기 수용적(Self-Contained) 특징을 가지고 있다.
- JWT 기반 인증은 쿠키/세션 방식과 유사하게 JWT 토큰(Access Token)을 HTTP 헤더에 실어 → 서버가 클라이언트를 식별하도록 한다.
JWT 사용
- 로그인
- 클라이언트가 ID + Password로 로그인을 요청
- 서버가 ID + Password 일치 여부를 확인하고, 유효할 경우 토큰(JWT)를 발급
- 클라이언트가 다음에 어떤 요청을 할 때, 발급받은 인증 토큰을 헤더에 포함시켜 요청
- 서버에 요청이 오면, 헤더에 포함된 인증 토큰을 해석해 권한 확인
- 정보교류
- 두 개체 사이에서 안정성 있는 정보 교환 가능
- 정보가 내장되어 있어, 정보를 보낸 이가 바꾸거나 조작하지 않았는지에 대한 사실 검증 가능
🔗 JWT의 구조
- JWT는 Header(헤더) . Payload(페이로드) . Signature(서명) 세 부분을 ‘ . ‘ (구분자)으로 구분한다.
💡 aaaa . bbbb . cccc
헤더 내용 서명
- Header
- [alg]와 [typ]의 두 가지 정보로 구성
- alg : Signature를 해싱하기 위한 알고리즘 지정
- 토큰 검증 시 사용되는 Signature 부분에서 사용
- Ex) HS256(SHA256) or RSA
- typ : 토큰의 타입 지정
- Ex) JWT
- alg : Signature를 해싱하기 위한 알고리즘 지정
{
"alg": "HS256",
"typ": JWT
}
2. Payload
- 토큰에 담을 정보를 지님
- 클라이언트의 고유 ID 값, 유효기간 등이 포함되어 있음
- key-value 형식으로 이루어진 한 쌍의 정보를 Claim(클레임) 이라고 칭함
- 토큰에는 여러 개의 클레임을 넣을 수 있다.
{ "sub": "123456789", "name": "Mi Gyeong", "lat": 1516239022 }
- 클레임의 종류
- 등록된(Registered) 클레임
- 토큰의 정보를 표현하기 위해 이미 정해진 종류의 데이터
- 서비스에 필요한 정보가 아닌, ‘토큰에 대한 정보'를 담기 위한 클레임이다.
- 선택적으로 작성 가능하다.
- Key의 String 길이는 3이다.
- subject는 유니크한 값으로, 사용자 이메일을 사용한다.
Key Value iss(issuer) 토큰 발급자 sub(subject) 토큰 제목 aud(audience) 토큰 대상자 exp(expiration) 토큰 만료 시간 - 항상 현재 시간 이후로 설정 -> NumericDate 형식Ex) 1480849147370 nbf(not before) 토큰 활성 날짜 - 해당 날짜 전의 토큰은 비활성화 상태 iat(issued at) 토큰 발급 시간 - 토큰 발급 이후 경과 시간(토큰의 age) jti(JWT ID) JWT 토큰 식별자 - 중복 방지 및 일회용 토큰(Access Token) 등에 사용 - 공개(Public) 클레임
- 사용자 정의 클레임
- 공개용 정보를 위해 사용
- 충돌 방지를 위한 이름으로 URI 포멧 사용
{ "<https://simmigyeong.tistory.com/>": true }
- 비공개(Private) 클레임
- 사용자 정의 클레임
- 서버와 클라이언트 사이에 임의로 지정한(필요한) 정보를 저장
- 공개 클레임과 달리, 중복 시 충돌 가능성이 있어 사용 시 유의해야 함
{ "username": "migyeong" }
- 등록된(Registered) 클레임
3. Signature
- Signature는 인코딩된 Header와 Payload를 더한 뒤 비밀키로 해싱하여 생성한 암호화 코드이다.
- Header와 Payload는 단순히 인코딩된 값이므로, 제 3자가 복호화 및 조작할 수 있지만,
- 서명에 사용되는 비밀키는 외부에 노출되지 않도록 주의해야 한다!!
- 비밀키가 외부에 노출되는 경우, 누구나 서버 인증을 통과하는 Signature를 만들 수 있으므로, 인가되지 않은 요청들이 통과될 수 있다.
- Signature는 서버 측에서 관리하는 비밀키가 유출되지 않는 이상, 복호화할 수 없다.
- Signature는 토큰의 위변조 여부를 확인하는 데 사용된다.
- Signature 생성 과정
- Header(헤더)와 Payload(페이로드)의 값을 각각 BASE64로 인코딩하고,
- 인코딩한 값을 비밀 키를 이용해 헤더에서 정의한 알고리즘으로 해싱을 하고
- 이 값을 다시 BASE64로 인코딩하여 생성한다.
HEADER | PAYLOAD | VERIFY SIGNATURE |
{ "alg": "HS256", "typ": "JWT"} | { "sub": "1234567890", "name": "Sim", "iat": 1516239022} | HMACSHA256( base64UrlEncode(header) + " . " + base64UrlEncode(payload) ) 한 값을 Base64 인코딩 |
- 헤더와 페이로드, 서명에 해당하는 내용이 각각 인코딩되어 JWT로 나타나는 결과값은 아래와 같다.
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IlNpbSIsImlhdCI6MTUxNjIzOTAyMn0.1MjAckWhJVC91zNAL9lfbT0TU-5eUNKUKFujNLABmPA
❗️ Access Token & Refresh Token
⏱ 토큰의 만료 시간
- 토큰을 한 번 발행하고 → 클라이언트에 보내고 나면, 이후 서버에서는 토큰을 파괴시킬 방법이 존재하지 않는다.
- 보통 JWT 토큰은 클라이언트 로컬 Storage에 저장하고 사용하게 되는데, 이때 토큰의 탈취 현상이 일어난다면?
- → 해당 토큰을 서버에서 제어할 수 없는 문제가 발생한다.
💡 따라서, 토큰을 발행할 때는 만료시간을 필수로 넣어주어야 한다.
- 그렇다면, 토큰의 만료 시간을 무조건 짧게 해야할까?
- 물론, 보안을 위해서라면 만료 시간을 짧게 설정하는 것이 맞는 방법 같지만,
- 막연하게 짧게 설정할 경우, 토큰이 만료될 때마다 사용자는 다시 로그인을 하거나/서버는 매번 토큰을 새로 발행해야 한다.
- 그렇다고, 토큰의 만료시간을 무제한으로 늘려야 할까?
- 사용자의 편리함과 서버의 부하를 줄이기 위해서라면, 토큰의 만료시간을 무조건 늘리는 게 좋을 것이지만,
- 보안에 취약하다는 치명적인 문제가 발생한다.
- 이러한 토큰의 만료시간 문제를 적당히 보완하고, 중간 지점을 맞추기 위해 등장한 것이 Access Token 과 Refresh Token 이다!
🗝 Access Token
- 리소스에 직접 접근할 수 있도록 해주는 정보만을 가지고 있다.
- Refresh Token에 비해 짧은 만료 시간을 가진다.
🗝 Refresh Token
- 새로운 Accss Token을 발급받기 위한 정보를 가지고 있다.
- 클라이언트가 Access Token이 없거나 만료될 경우 → Refresh Token을 통해 서버에 요청해서 새로운 Access Token 을 발급받을 수 있다.
- Access Token에 비해 긴 만료 시간을 갖는다.
- 외부에 노출되지 않도록 관리하기 위해 DB에 저장한다.
🔑 JWT의 인증 과정
1. Autorization Grant
- 사용자가 ID와 Password를 통해 로그인 요청을 보내 권한을 요청한다.
2. Access Token 발급
- 로그인이 정상적으로 완료되면(인증에 성공할 경우) JWT, Access Token, Refresh Token 을 발급한다.
3. Access Token을 이용해 API를 요청
- 클라이언트가 Resource Server(특정 서비스를 제공하는 서버)에 접근을 요청할 때, 발급받은 토큰을 Request Header를 통해 Resource Server 에 보낸다.
4. Protected Resource 응답
- Resource Server가 Access Token을 받아 검증한다.
- Access Token에 문제가 없다면 요청에 정상적으로 응답한다.
5. Access Token이 만료되면
6. Access Token 재발급 요청
- 클라이언트가 토큰 만료 신호를 받게 되면, 토큰을 재발급 받는 API로 Refresh Token을 보내 재발급을 요청한다.
7. Access Token 재발급
- Reresh Token이 정상적인 토큰인지 확인한 후 Access Token 을 발급한다.
⭕️ JWT의 장점
- Hader와 Payload를 통해 Signature를 생성하므로, 데이터 위변조를 방지할 수 있다.
- 인증 정보에 대한 별도의 저장소가 필요없다.
- JWT는 토큰의 기본정보, 전달할 정도, 토큰의 검증을 증명하는 서명 등 필요한 모든 정보를 자체적으로 지니고 있다.(Self-Contained)
- 트래픽(서버와 스위치 등 네트워크 장치에서 일정 시간 내에 흐르는 데이터의 양)에 대한 부담이 낮다.
- 클라의언트의 인증 정보를 저장하는 세션과 다르게, 서버는 Stateless 상태이다.
- 확장성(로그인 정보가 사용되는 분야의 확장성)이 우수하다.
- 토큰 기반으로, 다른 로그인 시스템에 접근 및 권한 공유가 가능하다.
- OAuth의 경우 소셜 계정을 이용해 다른 웹서비스에서도 로그인이 가능하다.
- 모바일 어플리케이션 환경에서도 잘 동작한다.
- REST 서비스로 제공 가능하다.
❌ JWT의 단점
- 쿠키/세션과 달리 JWT는 토큰의 길이가 길어 → 인증 요청이 많아질수록 네트워크 부하가 심해진다.
- 모든 요청에 대해 토큰을 전송하면 → 토큰에 담기는 정보가 많아지고 → 네트워크 부하가 증가할 것
- 토큰을 탈취당할 경우, 대처하기 어렵다.
- 따라서, Payload에 중요한 정보를 담아서는 안 된다.
- 토큰은 발급 이후 유효기간이 만료될 때까지 계속해서 사용이 가능하므로, 즉 임의로 삭제가 불가능하므로 만료 시간을 필수로 지정해야 한다.
🔍 JWT와 Cookie/Session 의 차이
장점 | 단점 | |
Cookie & Session | 1. Cookie 만 사용하는 방식보다 보안성이 향상 2. 서버 쪽에서 Session의 통제 가능 3. 네트워크 부하 낮음 |
세션 저장소 사용으로 인한 서버 부하 |
JWT | 1. 인증을 위한 별도의 저장소가 필요 없고 2. 별도의 I/O 작업 없이 빠른 인증 처리 가능 3. 확장성 우수 |
1. 토큰의 길이가 늘어날수록 네트워크 부하 2. 특정 토큰을 강제 만료시키기 어려움 |
🔖 참고 자료
'Web > Concept' 카테고리의 다른 글
[Web] 서버 기반 인증 시스템과 토큰 기반 인증 시스템 (0) | 2022.05.22 |
---|---|
[Web] Authentication & Autorization (0) | 2022.05.22 |
[Web] 쿠키(Cookie) & 세션(Session) (0) | 2022.05.22 |
[Web] JWT(JSON Web Token) (0) | 2022.01.13 |