1️⃣ JWT 정의
- JWT(Json Web Token)은 쿠키와 세션의 사용중 나타난 하나의 인터넷 표준 인증 방식
- 인증에 필요한 정보들을 Token에 담아 암호화시켜 사용하는 토큰
- 토큰에 대한 정보, 전달한 정보, 토큰이 검증되었음을 증명하는 서명된 토큰임
- 공개/개인 키를 쌍으로 사용함 -> 토큰에 서명할 경우, 서명된 토큰은 개인 키를 보유한 서버가 이 서명된 토큰이 정상적인 토큰인지 인증할 수 있음
토큰이란?
토큰(Token)은 말 그대로 동전이라는 뜻 이지만, 웹 상에서는 특정한 목적으로만 사용 가능한 동전에 일종의 권한를 주는 것을 말한다.
서버에서는 사용자가 결제한 돈도 오고가므로 권한이라는것이 중요하다.
인터넷에 사이트를 올리면 전 세계의 사용자들이나 해커들이 접근 가능한데, 이때 사용자들의 돈을 보호하려면 본인만 접근 가능하도록 본인 확인 수단 이 필요한데 그 수단으로 토큰을 이용한다.
2️⃣ JWT 구조
- JWT 구조는 점(.) 으로 구분된 3 부분으로 이루어져 있다.
- Header
- Payload
- Signature
- 아래처럼 각각의 구성 요소가 .으로 구분되어있는 형태
- xxxxx.yyyyy.zzzzz
💚 Header
- header는 토큰의 타입이나, 서명 생성에 어떤 알고리즘이 사용되었는지 저장
{
"typ": "JWT",
"alg": "HS512"
}
- 현재 토큰의 타입이 JWT임
- 개인키로 HS512 알고리즘이 적용되어 암호화가 되어있음
💚 Payload
- 실제 보관할 데이터를 JSON 형식으로 나타낸다.
- payload 에 담기는 정보의 한 '조각'을 클레임(claim) 이라고 부른다
- name/value 한쌍
- key-value의 형태로 저장
{
"sub": "1",
"iss": "ori",
"exp": 1636989718,
"iat": 1636987918
}
- 토큰에는 여러개의 클레임들이 들어간다.
클레임의 유형
1️⃣ 등록된 (registered) 클레임
- 토큰 정보를 표현하기 위해 이미 정해진 종류의 데이터들.
- 사용자 정의 클레임으로 공개용 정보를 위해 사용된다.
- 충돌이 방지된(collision-resistant) 이름을 가져야 한다.
- 충돌을 방지하기 위해 클레임 이름은 URL 형식으로 짓는다.
{ "https://naver.com": true }
3️⃣ 비공개 (private) 클레임
- 사용자 정의 클레임으로 서버와 클라이언트 사이에 임의로 지정한 정보를 저장한다.
- 이름이 중복되어 충돌이 가능하므로 유의해서 사용해야한다.
{ "username": "velopert" }
- 가장 중요한것은 payload에 민감한 정보를 담지않는 것
- 위에 header와 payload는 json이 디코딩되어있을 뿐 특별한 암호화가 걸려있는 것이 아님
- jwt.io에서 서버에서 생성한 JWT를 넣기만해도 볼 수 있는 화면
- JWT에서 header와 payload는 특별한 암호화없이 흔히 사용할 수 있는 base64 인코딩을 사용하기 때문에
서버가 아니더라도 그 값들을 확인 가능 - 따라서 누구나 jwt를 가지고 디코딩을 한다면 header나 payload에 담긴 값을 알 수 있음
- 위에 header와 payload는 json이 디코딩되어있을 뿐 특별한 암호화가 걸려있는 것이 아님
JWT는 단순히 "식별을 하기위한" 정보만을 담아두어야 함
💚 Signature
- 토큰을 인코딩하거나 유효성 검증을 할 때 사용하는 고유한 암호화 코드
- 지금까지 Header와 Payload를 보여줄 때는 인코딩 되어있던 값들을 JWT에 담겨있는 것처럼 디코딩된 상태를 사용했음
- header를 디코딩한 값, payload를 디코딩한 값을 위처럼 합치고 이를 your-256-bit-secret 즉, 서버가 가지고 있는 개인키를 가지고 암호화되어있는 상태
- 따라서 signature는 서버에 있는 개인키로만 암호화를 풀 수 있으므로 다른 클라이언트는 임의로 Signature를 복호화 할 수 없음
- 복호화와 인증 과정
- JWT 토큰을 클라이언트가 서버로 요청과 동시에 전달한다.
- 서버가 가지고있는 개인키를 가지고 Signature를 복호화한 다음 base64UrlEncode(header)가 JWT의 heaer값과 일치한지, base64UrlEncode(payload) 와 일치한지 확인하여 일치한다면 인증을 허용합니다.
- 만약 클라이언트가 payload에 담긴 식별자가 변조된 JWT로 요청을 함
-> 서버가 애초에 발급했던 Signature 안의 payload와 다르기 때문에 인증이 불가
3️⃣ JWT의 장, 단점
💚 JWT의 장점
- Header와 Payload로 signature를 생성하기 때문에 데이터가 위,변조되었을 때 더 쉽게 판별할 수 있다.
- Session과 달리
- 별도 저장소가 불필요하다.
- 서버를 stateless로 유지할 수 있다.
- 정보를 자체적으로 보유할 수 있어 요청할 때마다 DB조회를 하지않아도 된다.
- 모바일 환경에서도 잘 동작한다.
💚 JWT의 단점
- token의 길이가 길어 인증 요청이 많아질수록 네트워크 부하 위험이 있다.
- token은 탈취당할 경우 대처하기가 어렵다.
- token의 만료시간을 설정해두었을 경우, 그 전에 강제로 만료시키기 어렵다.
- payload의 내용은 암호화가 되지않아, Server와 Client간에 나누는 내용에 중요한 정보 (ex. 고객 개인정보)를 담을 수는 없다.
💚 Cookie&Session 인증 방식 & JWT 인증 방식 비교
인증 방식 | 장점 | 단점 | |
Cookie & Session 인증 방식 |
서버 기반 | 네트워크 부담 낮음 | Session 저장소가 필요해 서버 부하 위험 |
JWT 인증 방식 | 토큰 기반 | 별도의 저장소가 필요치않고 DB조회를 하지않아도 되므로 서버 부담 낮음 |
토큰 길이가 길어질수록 네트워크 부하 위험 |
4️⃣ Refresh Token?
💚 Access Token 의 문제
- Access Token(JWT)를 통한 인증 방식의 문제
- 만일 제 3자에게 탈취당할 경우 보안에 취약함
- 유효기간이 짧은 Token의 경우 그만큼 사용자는 로그인을 자주 해서 새롭게 Token을 발급받아야 하므로 불편
- 그러나 유효기간을 늘리자면, 토큰을 탈취당했을 때 보안에 더 취약, 적절한 유효기간 설정 필요
이때 “그러면 유효기간을 짧게 하면서 좋은 방법이 있지는 않을까?”라는 질문의 답 -> Refresh Token
💚 Refresh Token
- Refresh Token은 Access Token과 똑같은 형태의 JWT임
- 처음에 로그인을 완료했을 때 Access Token과 동시에 발급되는 Refresh Token은 긴 유효기간을 가짐
- Access Token이 만료됐을 때 새로 발급해주는 열쇠가 됨
(여기서 만료라는 개념은 그냥 유효기간을 지났다는 의미)
ex. Refresh Token의 유효기간은 2주, Access Token의 유효기간은 1시간
사용자는 API 요청을 하다가 1시간이 지나게 되면, 가지고 있는 Access Token은 만료
그러면 Refresh Token의 유효기간 전까지는 Access Token을 새롭게 발급받을 수 있다.
💚 Access Token + Refresh Token 인증 과정
1. 사용자가 ID , PW를 통해 로그인
2. 서버에서는 회원 DB에서 값을 비교(보통 PW는 일반적으로 암호화해서 들어갑니다)
3~4. 로그인이 완료되면 Access Token, Refresh Token을 발급, 이때 일반적으로 회원DB에 Refresh Token을 저장
5. 사용자는 Refresh Token은 안전한 저장소에 저장 후, Access Token을 헤더에 실어 요청 보냄
6~7. Access Token을 검증하여 이에 맞는 데이터를 보냄
8. Access Token 만료시
9. 사용자는 이전과 동일하게 Access Token을 헤더에 실어 요청 보냄.
10~11. 서버에서 Access Token의 만료를 확인 후 권한 없음 신호 보냄.(서버 -> 사용자)
** Access Token 만료가 될 때마다 계속 Access Token 만료시 (8~11) 과정을 거칠 필요 없음
사용자(프론트엔드)에서 Access Token의 Payload를 통해 유효기간을 알 수 있다. 따라서 프론트엔드 단에서 API 요청 전에 토큰이 만료됐다면 바로 재발급 요청을 할 수도 있음
12. 사용자는 Refresh Token + Access Token을 서버로 보냄.
13. 서버는 받은 Access Token이 조작되지 않았는지 확인한후, Refresh Token과 사용자의 DB에 저장되어 있던 Refresh Token을 비교함, Token이 동일하고 유효기간도 지나지 않았다면 새로운 Access Token을 발급
이후 서버는 새로운 Access Token을 헤더에 실어 다시 API 요청을 진행 (요청 응답 요청 응답...)
💚 Refresh Token 장점
- 기존의 Access Token만 있을 때보다 안전
💚 Refresh Token 단점
- 검증 프로세스가 길기 때문에 구현이 복잡
- Access Token 이 만료될 때마다 새롭게 발급하는 과정에서 생기는 HTTP 요청 횟수가 많아지며 서버의 자원 낭비 발생
💻 reference
'Server > Spring Boot' 카테고리의 다른 글
[Chapter 04] 머스테치로 화면 구성하기 (0) | 2023.10.16 |
---|---|
[Spring Boot] ERD (Entity Relationship Diagram) 란? (0) | 2023.10.15 |
[Spring] DAO, Entity, DTO, VO의 개념과 비교 (0) | 2023.09.25 |
[Spring Boot] 빌더(Builder) 패턴의 정의, 생성자 패턴 빌더 패턴 비교 (0) | 2023.09.25 |
[Spring] 스프링 의존성 주입 종류와 @RequiredArgsConstructor 어노테이션을 사용한 생성자 주입 (0) | 2023.09.24 |