Stateless 서버의 토큰 기반 인증 방식 (JWT)

johan1103·2022년 9월 15일

토큰 기반 인증 방식, JWT

JWT는 Json Web Token의 약자로, Json형식의 데이터 기반으로 만들어진 토큰입니다.

모든 토큰은 만들기 위해서는 크게 3가지 정보 Header, Payload, Signature가 필요합니다.

토큰의 기본 구조

이미지 출처 ([WEB] 📚 JWT 토큰 인증 이란? - 💯 이해하기 쉽게 정리)

  • Header

    {
    	"alg" : "HS256",
    	"typ" : "JWT"
    }

    Header, Payload, Signature중 유일하게 Signature만 암호화를 거쳐서 만들어 지는데, 이때 어떤 암호화 알고리즘을 사용할 지, Header 에 명시합니다.

    토큰의 종류를 입력합니다. JWT 토큰을 만들 때에는 “JWT”가 value값으로 들어갑니다.

  • Payload

    {
    	"sub" : "1234567889",
    	"name" : "John Doe",
    	"iat" : 1516239022
    }

    토큰에서 사용할 정보의 조각들이 담겨있습니다. 이러한 key, value 한쌍을 claim이라고 합니다.

    페이로드 내부의 클래임들은 단순히 인코딩 되어 있는 정보들이기 때문에, 민감한 정보들을 넣어서는 안됩니다. 유저임을 식별할 수 있는 값이면 충분합니다.

    페이로드 내부에 정해진 필수 입력 데이터는 없지만 대표적인 값들은 존재합니다.

    (발행자, 만료 시간, 제목, 발행 시간 , JWI아이디 등등)

  • Signature
    이미지 출처 ([WEB] 📚 JWT 토큰 인증 이란? - 💯 이해하기 쉽게 정리)

    헤더에서 정한 알고리즘을 사용합니다.

    시그니처는 (헤더 + 페이로드) + 서버가 가지고 있는 유일한 key값을 합친 것을 헤더에서 정의한 알고리즘으로 암호화를 해서 구성됩니다.

    서버가 가지고 있는 유일한 key값을 가지고 암호화 되기 때문에 토큰을 탈취해서 암호화 알고리즘을 알아낸다 해도, 해커는 유효한 토큰을 생성해내지 못합니다.

    💡
    Header와 Payload는 단순히 인코딩된 값이기 때문에 제 3자가 복호화 및 조작할 수 있지만, Signature는 서버 측에서 관리하는 비밀키가 유출되지 않는 이상 복호화할 수 없다.따라서 Signature는 토큰의 위변조 여부를 확인하는데 사용된다.

🔐 JWT 인코딩 / 디코딩 해보기

직접 JWT 토큰을 생성해보고 싶다면 아래 사이트에서 실습해보실 수 있습니다.

JWT.IO

JWT를 이용한 인증 과정


이미지 출처 ([WEB] 📚 JWT 토큰 인증 이란? - 💯 이해하기 쉽게 정리)

  1. 클라이언트가 ID,PW를 입력하여 서버에 로그인 인증을 요청한다.

  2. 서버에서 클라이언트로부터 인증 요청을 받으면 Header, PayLoad, Signature를 정의한다.

    Header, PayLoad, Signature를 각각 Base64로 인코딩 한 뒤 Signature는 암호화를 한 후 JWT를 생성하고 쿠키에 토큰을 담아서 클라이언트에게 발급한다.

  3. 클라이언트는 서버로부터 받은 JWT를 로컬 스토리지 혹은 쿠키저장소에 저장한다.

    API를 서버에 요청할 때 해당 JWT토큰을 담아서 보낸다.

  4. 서버가 할 일은 클라이언트가 Header에 담아서 보낸 JWT가 내 서버에 발행한 토큰인지 일치 여부를 확인한다. 즉, 클라이언트에게 받은 헤더와 페이로드 & 서버가 가지고 있는 개인 키 를 합쳐서 헤더에 명시된 암호화 알고리즘으로 시그니쳐를 만들어본다. 서버가 그자리에서 만든 시그니처와 클라이언트가 전달해준 시그니처가 정확히 일치하면 해당 토큰은 위조된것이 아니라는 사실이 보장된다.

  5. 인증이 완료되면 서버는 페이로드에 들어있는 유저의 정보들을 통해서 클라이언트의 유저를 식별한뒤, 해당 유저에 맞는 서비스를 제공해서 응답을 한다.

  6. 클라이언트가 서버에 요청을 했는데, 만일 엑세스 토큰의 시간이 만료되면 클라이언트는 리프래시 토큰을 이용해서 서버로부터 새로운 엑세스 토큰을 발급 받는다.

토큰이 위조로부터 확실한 인증 신뢰성을 가지는 이유

유저1이 발급 받은 토큰의 헤더, 페이로드, 시그니처를 각각 A,B,C라고 가정하겠습니다.

또한 어떤 유저2가 위조를 해서 타 유저3이 로그인 한것으로 위장하려는 의도를 가지고 있다고 가정하겠습니다.

유저2는 유저1이 발급받은 토큰을 탈취해서 유저 3에 맞는 페이로드 B’를 작성한 뒤, 서버에 전송을 하게 되면 서버는 A + B’ + C로 이루어진 토큰을 받게 됩니다.

그러나 서버가 확인을 위해 A + B’와 서버의 개인키로 시그니처를 만들게 되면 C가 아닌 다른 시그니처가 만들어 져서 인증에 실패하게 됩니다.

정리하자면, 서버는 토큰 안에 들어있는 정보가 무엇인지 아는게 중요한 것이 아니라 해당 토큰이 유효한 토큰인지 확인하는 것이 중요하기 때문에, 클라이언트로부터 받은 JWT의 헤더, 페이로드를 서버의 key값을 이용해 시그니처를 다시 만들고 이를 비교하며 일치했을 경우 인증을 통과시킵니다.

💡

JWT은 서명(인증)이 목적이다.

JWT는 Base64로 암호화를 하기 때문에 디버거를 사용해서 인코딩된 JWT를 1초만에 복호화할 수 있다.

복호화 하면 사용자의 데이터를 담은 Payload 부분이 그대로 노출되어 버린다. 그래서 페이로드에는 비밀번호와 같은 민감한 정보는 넣지 말아야 한다.

그럼 토큰 인증 방식 자체가 빛 좋은 개살구라고 생각할수도 있지만, 토큰의 진짜 목적은 정보 보호가 아닌, 위조 방지이다.

바로 위에서 소개했듯이, 시그니처에 사용된 비밀키가 노출되지 않는이상 데이터를 위조해도 시그니처 부분에서 바로 걸러지기 때문이다.

JWT의 장점

  1. 헤더와 페이로드를 가지고 다시 시그니처를 생성해서 비교하는 인증방식이므로 데이터 위변조를 막을 수 있습니다.
  2. 인증 정보에 대한 별도의 저장소가 필요 없습니다.
  3. JWT는 토큰에 대한 기본 정보와 전달할 정보 및 토큰이 검증됬음을 증명하는 서명 등 필요한 모든 정보를 자체적으로 지니고 있습니다.
  4. 클라이언트 인증 정보를 저장하는 세션과 다르게, 서버는 무상태(StateLess)가 됩니다.
  5. 확장성이 우수합니다.
  6. Oauth를 활용하는 경우 소셜 계정을 이용해서 다른 웹 서비스에도 로그인을 할 수 있습니다.
  7. 모바일에서도 잘 작동합니다. (모바일은 세션 사용이 불가능)

JWT의 특장점

서버에서 가장 피해야 할 것은 데이터베이스 조회이다.

서버 자체가 죽는 경우도 있지만, 대부분 DB가 터져서 서버도 같이 죽는 경우가 허다하기 때문이다.

이런 점에서, JWT 토큰은 DB조회를 안해도 되는 장점을 가지고 있다는 점이다.

만일 payload에 유저이름 과 유저등급 을 같이 두고 보내면, 서버에서는 유저이름을 가지고 DB를 조회해서 유저 등급을 얻지않아도 바로 원하는 정보를 취할수 있다.
(물론 이런 정보는 탈취해서 값 자체는 해커가 볼 수 있개 때문에 노출 되도 괜찮은 정보만 넣어야 한다.)

JWT 단점

  1. 쿠키 세션과 다르게 JWT는 토큰의 길이가 길기 때문에, 인증 요청이 많아질수록 네트워크 부하가 심해집니다.
  2. Payload 자체는 암호화 되지 않기 때문에 유저의 중요한 정보는 담을 수 없습니다.
  3. 토큰을 탈취당하면 그 토큰을 변조는 못하지만 그대로 사용해서 서버에 권리를 행사할 수 있습니다.

💡 JWT의 마지막 3번 단점 때문에 Access Token, Refresh Token 방식이 존재합니다.

꼬리 지식

  • 인코딩 인코딩은 정보의 형태나 형식을 표준화,보안,처리속도 향상, 저장 공간 절약등을 위해 다른 형태나 형식으로 변환하는 처리 혹은 처리 방식을 말한다.
  • base64인코딩 base64 text를 binary data로 바꾸는 처리것을 base64인코딩이라고 한다. (base64를 직역하면 64진법이라는 뜻임.) 인코딩 과정 문자열 → ASCII binary(한 글자당 8bit) → 전부 모아서 다시 6bit씩 분해 → 그 6bit를 다시 문자로 변환 이렇게 해서 생긴 문자열이 base64인코딩의 결과물이다. 그런데 그렇게 하면 데이터 양이 길어지기 때문에 overhead가 발생하는데 왜 이걸 쓰는걸까?
    • base64를 쓰는 이유 문자를 전송하기 위해 설계된 Media(Email, HTML)를 이용해 플랫폼 독립적으로 Binary Data(이미지나 오디오)를 전송 할 필요가 있을 때, ASCII로 Encoding하여 전송하게 되면 여러가지 문제가 발생할 수 있다. 대표적인 문제는
      • ASCII는 7 bits Encoding인데 나머지 1bit를 처리하는 방식이 시스템 별로 상이하다.

      • 일부 제어문자 (e.g. Line ending)의 경우 시스템 별로 다른 코드값을 갖는다.

        위와 같은 문제로 ASCII는 시스템간 데이터를 전달하기에 안전하지가 않다. Base64는 ASCII 중 제어문자와 일부 특수문자를 제외한 64개의 안전한 출력 문자만 사용한다.(* 안전한 출력 문자는 문자 코드에 영향을 받지 않는 공통 ASCII를 의미한다).

        즉, 정리하면 어떤 시스템에서 데이터를 읽더라도 동일한 내용으로 읽어 낼 수 있는 것을 보장하기 위해서 base64인코딩을 하는것이다.

참고 자료

https://effectivesquid.tistory.com/entry/Base64-인코딩이란

https://inpa.tistory.com/entry/WEB-📚-JWTjson-web-token-란-💯-정리#top

Base64 인코딩이란?

0개의 댓글