[DEV] J-Jay

토큰 기반 인증방식 - JWT 본문

Back-end/기본상식

토큰 기반 인증방식 - JWT

J-Jay 2023. 9. 10. 18:42
728x90

사용자가 서버에 접근할 때 이 사용자가 인증된 사용자인지 확인하는 방법은 다양하다.

대표적인 사용자 인증 확인 방법에는 서버 기반 인증과 토큰 기반 인증이 있다.

 

서버기반 인증

스프링 시큐리티에서는 기본적으로 세션 기반 인증을 제공해 준다.

아래 글을 참고 바란다.

https://dev-junick.tistory.com/57

 

스프링 부트 - 로그인/로그아웃 구현

스프링 시큐리티 설정 build.gradle (의존성 추가) dependencies { //스프링 시큐리티를 사용하기 위한 스타터 의존성 implementation 'org.springframework.boot:spring-boot-starter-security' //타임리프에서 스프링 시큐리

dev-junick.tistory.com

 

토큰기반 인증

토큰기반 인증은 토큰을 사용하는 방법이다. 토큰은 서버에서 클라이언트를 구분하기 위한 유일한 값인데 서버가 토큰을 생성해서 클라이언트에게 제공하면, 클라이언트는 이 토큰을 갖고 있다가 여러 요청을 이 토큰과 함께 신청한다.

그럼 서버는 토큰만 보고 이 사용자가 유용한 사용자인지 검증하는 것이다.

 

토큰 전달, 인증 과정

토큰 기반 인증 특징(무상태성, 확장성, 무결성)

 

무상태성

무상태성은 사용자의 인증 정보가 담겨 있는 토큰이 서버가 아닌 클라이언트에 있으므로 서버에 저장할 필요가 없다.

서버가 뭔가 데이터를 유지하고 있으려면 그만큼 자원을 소비해야하기 떄문이다.

토큰 기반 인증에서는 클라이언트에서 인증 정보가 담긴 토큰을 생성하고 인증한다. 따라서 클라이언트에서는 사용자의 인증 상태를 유지하면서 이후 요청을 처리해야 하는데 이것을 "상태를 관리한다" 라고 한다. 이렇게 하면 서버 입장에서는 클라이언트의 인증 정보를 저장하거나 유지하지 않아도 되기에 완전한 무상태로 효율적인 검증이 가능하다.

 

확장성

무상태성은 확장성에 영향을 준다. 서버를 확장할 때 상태 관리를 신경 쓸 필요가 없으니 서버 확장에도 용이한 것이다.

예를 들어 물건을 파는 서비스가 있고, 결제를 위한 서버와 주문을 위한 서버가 분리되어 있다고 가정해 보면

세션 인증 기반은 각각 API에서 인증을 해야 되는 것과는 달리 토큰 기반 인증에서는 토큰을 가지는 주체는 서버가 아니라 클라이언트이기 때문에 가지고 있는 하나의 토큰으로 결제 서버와 주문 서버에게 요청을 보낼 수 있다.

추가로 페이스북 로그인, 구글 로그인 같이 토큰 기반 인증을 사용하는 다른 시스템에 접근해 로그인 방식을 확장 할 수
있고, 이를 활용하여 다른 서비스에 권한을 공유할 수 있다.

 

무결성

토큰 방식은 HMAC(hash-based message authentication)기법 이라고도 부른다.

토큰을 발급한 이후에는 토큰 정보를 변경하는 행위는 할 수 없다. 즉, 토큰의 무결성이 보장된다. 만약 누군가 토큰을 

한 글자라도 변경하면 서버에서는 유효하지 않은 토큰이라고 판단한다.


JWT(Json Web Token)

JWT를 이용해 인증하려면 HTTP 요청 헤더 중에 Authorization 키 값에 Bearer + JWT 토큰 값을 넣어 보내야 한다.

JWT는 .을 기준으로 헤더(Header), 내용(Payload), 서명(Signature)으로 이루어져 있다. 

헤더(Header)

토큰의 타입과 해싱 알고리즘을 지정하는 정보를 담는다. 

  • typ: 토큰의 타입을 지정한다. JWT라는 문자열이 들어가게 된다
  • alg: 해싱 알고리즘을 지정한다.
{
 "typ" : "JWT",
 "alg" : "HS256"
}

 

내용(Payload)

토큰과 관련된 정보를 담는다. 내용의 한 덩어리를 클레임(Claim)이라고 부르며,
클레임은 키 값의 한 쌍으로 이루어져 있다. 클레임은 등록된 클레임, 공개 클레임, 비공개 클레임으로 나눌 수 있다.

  • 등록된 클레임(토큰의 정보)
이름 내용
iss 토큰 발급자(issuer)
sub 토큰 제목(subject)
aud 토큰 대상자(audience)
exp 토큰의 만료 시간(expiration), 시간은 NumericDate 형식으로 한다. (현재시간 이후로 설정 必)
nbf 토큰의 활성 날짜와 비슷한 개념으로 nbf는 Not Before을 의미한다. NumericDate 형식으로
지정하며 이 날짜가 지나기 전까지는 토큰이 처리되지 않는다
iat 토큰이 발급된 시간으로 iat는 issued at을 의미한다

jti JWT의 고유 식별자로서 주로 일회용 토큰에 사용한다.
  • 공개 클레임, 비공개 클레임

공개 클레임은 충돌을 방지할 수 있는 이름을 가져야 하며, 보통 클레임 이름을 URI로 짓는다.

비공개 클레임은 공개되면 안되는 클레임을 의미하며 클라이언트와 서버 간으 통신에 사용된다.

 

서명 (Signature)

해당 토큰이 조작되었거나 변경되지 않았음을 확인하는 용도로 사용하며, 헤더의 인코딩 값과 내용의 인코딩값을 합친 후,

주어진 비밀키를 사용해 해시값을 생성한다.

 

 

토큰 유효기간

만약 토큰을 주고받는 환경이 보안에 취약해서 토큰 자체가 노출된다면, 예를 들어 영화 티켓을 구매했는데 이 티켓의 정보가 노출되어 다른 사람이 이 티켓으로 영화를 보려고 한다고 하면 어떻게 이 문제를 막을 수 있을까?

토큰은 이미 발급되면 그 자체로 인증 수단이 되므로 서버는 토큰과 함께 들어온 요청이 토큰을 탈취한 사람의 요청인지 확인할 수 없다. 이 부분을 해결하기 위해 리프레시 토큰이 있다.

 

리프레시 토큰

위의 상황에서 유효기간이 하루라면 하루동안은 그 토큰으로 무엇이든 할 수 있을 테니 큰일이다.

그렇다고 토큰의 유효기간이 짧으면 사용자 입장에서는 받은 토큰을 너무 짧은 시간만 활용할 수 있으니 불편하다.

리프레시 토큰은 이러한 문제를 해결해 주며, 리프레시 토큰은 액세스 토큰과 별개의 토큰이다. 사용자를 인증하기 위한 용도가 아닌 엑세스 토큰이 만료되었을 때 새로운 엑세스 토큰을 발급하기 위해 사용한다. 엑세스 토큰의 유효 기간은 짧게 설정하고, 리프레시 토큰의 유효기간은 길게 설정하면 공격자가 엑세스 토큰을 탈취해도 몇 분 뒤에는 사용할 수 없는 토큰이 되므로 안전해진다.

 

'Back-end > 기본상식' 카테고리의 다른 글

인증(Authentication) 인가(Authorization)  (0) 2023.09.09
API와 REST API  (0) 2023.09.03
Library 와 Framework  (0) 2023.08.30
IP와 Port  (0) 2023.08.29
데이터베이스(DB)  (0) 2023.08.28