[Web] JWT 인증이란

clean·2024년 4월 8일
0

mewsinsa 기록

목록 보기
3/7
post-thumbnail

mewsinsa 프로젝트를 하면서 JWT 인증을 스프링 시큐리티를 쓰지 않고 직접 구현하기로 하였습니다.
JWT가 뭔지, 그리고 어떤 과정으로 클라이언트가 서버에 인증을 할 수 있는지 알아야 구현할 수 있겠죠.
그래서 본격적인 구현에 들어가기 전에 JWT 인증의 개념에 대해 정리해보려고 합니다.

Token 기반 인증

토큰 기반 인증 시스템은 클라이언트가 서버에 접속을 하면 서버에서 해당 클라이언트에게 인증되었다는 의미로 토큰을 부여합니다. 이 토큰은 유일하며 토큰을 발급받은 클라이언트는 또 다시 서버에 요청을 보낼 때 요청 헤더에 토큰을 심어서 보냅니다. 그러면 서버에서는 클라이언트로부터 받은 토큰을 서버에서 제공한 토큰과의 일치 여부를 체크하여 인증 과정을 처리하게 됩니다.

기존 세션 기반 인즈은 서버가 파일이나 데이터베이스에 세션정보를 가지고 있어야하고, 이를 조회하는 과정이 필요하기 때문에 많은 오버헤드가 발생합니다. 하지만 토큰은 세션과는 달리 서버가 아닌 클라이언트에 저장되기 때문에 메모리나 스토리지 등을 통해 세션을 관리했던 서버의 부담을 덜 수 있습니다. 토큰 자체에 데이터가 들어있기 때문에 클라이언트에서 받아서 위조되었는지만 판별하면 되기 때문입니다.

토큰은 앱과 서버가 통신 및 인증할 때 가장 많이 사용됩니다.
왜냐하면 웹에는 쿠키와 세션이 있지만 앱에는 이들이 없기 때문입니다.


토큰 방식 로그인 과정을 정리하면 아래와 같습니다.

  1. 클라이언트가 서버에게 인증 정보를 보냅니다.
  2. 서버는 클라이언트가 보낸 정보를 확인하고, 올바른 정보라면 인증되었다는 의미에서 토큰을 응답으로 보냅니다.
  3. 클라이언트는 서버 측에서 전달받은 토큰 또는 쿠키를 스토리지에 저장해둡니다. 그리고 앞으로 서버가 요청을 할 때마다 해당 토큰을 Http 요청 헤더에 넣어서 보냅니다. (그림에서 Authorization: Bearer ... JWT 부분)
  4. 서버는 전달받은 토큰을 검증하고 요청에 응답합니다. 토큰에는 요청한 사람의 정보가 담겨있어서 서버는 DB를 조회하지 않고도 누가 요청했는지를 알 수 있습니다.

Token 방식의 단점

  • 쿠키, 세션과는 다르게 토큰 자체의 데이터 길이가 길어서 인증 요청이 많아질수록 네트워크 부하가 심해질 수 있습니다.
  • Payload 자체는 암호화되지 않아서 유저의 중요한 정보는 담을 수 없습니다.
  • 토큰을 탈취 당하면 대처하기가 어렵습니다. (따라서 사용 기간 제한을 설정하는 식으로 대처합니다.)

JWT(JSON Web Token)이란

JWT(JSON Web Token)이란 인증에 필요한 정보들을 암호화시킨 JSON 토큰을 의미합니다.

JWT는 JSON 데이터를 Base64 URL-safe Encode를 통해 인코딩하여 직렬화한 것이며, 토큰 내부에는 위변조 방지를 위해서 개인키를 통한 전자서명도 들어있습니다. 따라서 사용자가 JWT를 서버로 전송하면 서버는 서명을 검증하는 과정을 거치게 되며 검증이 완료되면 요청한 응답을 돌려줍니다.

Base64 URL-safe Encode
일반적인 Base64 Encode에서 URL을 오류없이 사용할 수 있도록 '+', '/'를 각각 '-', '_'로 바꾼 인코딩 방식입니다.

JWT의 구조

JWT는 .을 구분자로 하여 3가지 문자열의 조합으로 이루어져 있습니다.

  • 헤더(Header): JWT에서 사용할 타입과, 해시 알고리즘의 종류가 담겨 있습니다.
  • 페이로드(Payload): 서버에서 첨부한 사용자 권한 정보와 데이터가 담겨 있습니다.
  • 서명(Signature): Header, Payload를 Base64 URL-safe Encode한 후 Header에 명시된 해시함수를 적용하고 개인키(Private Key)로 서명한 전자 서명이 담겨 있습니다.

Payload

페이로드에는 서버와 클라이언트가 주고 받는 시스템에서 실제로 사용될 정보에 대한 내용이 담겨 있습니다.

페이로드에는 정해진 데이터 타입은 없지만, 대표적으로 Registered claims, Public claims, Private claims 이렇게 세가지로 나뉩니다.

  • Registered claim: 미리 정의된 클레임
    • iss: 발행자 (issuer)
    • exp: 만료 시간 (expireation time)
    • sub: 제목 (subject)
    • iat: 발행 시간 (issued At)
    • jti: id
  • Public claims: 사용자가 정의할 수 있는 클레임. 공개용 정보 전달을 위해 사용
  • Private claims: 해당하는 당사자들 간에 정보를 공유하기 위해 만들어진 사용자 지정 클레임. 외부에 공개되어도 상관 없지만 해당 유저를 특정할 수 있는 정보들을 담는다.

JWT를 이용한 인증 과정

  1. 사용자가 ID, PW를 입력해서 서버에 로그인 인증을 요청합니다.
  2. 서버에서 클라이언트로부터 인증 요청을 받으면, Header, PayLoad, Signature를 정의합니다.
  3. 클라이언트는 서버로부터 받은 JWT를 로컬 스토리지에 저장합니다. (쿠키에 저장할 수도 있습니다.)
  4. 서버에 API 요청을 보낼 때마다 요청 헤더의 Authorizaton에 액세스 토큰을 담아서 보냅니다.
  5. 서버는 클라이언트가 헤더에 담아서 보낸 JWT가 현재 서버에서 발행한 제대로 된 토큰인지 일치 여부를 확인하고 일치한다면 인증을 통과 시키고 아니라면 통과 시키지 않습니다.
  6. 인증이 통과되면 페이로드에 들어있는 유저의 정보들을 select해서 클라이언트에게 돌려줍니다.
  7. 클라이언트가 서버에 요청을 보내려고 할 때 액세스 토콘이 만료된 상태라면, 리프레시 토큰을 실어 보냅니다.
  8. 서버는 리프레시 토큰을 보고 새로운 액세스 토큰을 발급합니다.

Reference

profile
블로그 이전하려고 합니다! 👉 https://onfonf.tistory.com 🍀

0개의 댓글