HTTP 인증 - JWT

ZZ3n·2020년 8월 9일
2

HTTP

목록 보기
3/3

jwt.io

JWT.IO 에서 작성해볼 수 있다.

💥 Stateless VS Stateful

  • Stateful과 Stateless의 차이에서 중요한 점은 당연 State다.
    여기서 State는 간략하게는 클라이언트와 서버의 연결상태를 말한다.

클라이언트와 서버의 연결 상태를 내가 관여한다? ➡ Stateful
클라이언트와 서버가 연결되는 아니든 신경쓰지 않는다? ➡ Stateless

  • Stateless를 사용하는 이유는 확장성과, 자원에 있다.

  • Stateless는 서버 확장시에 클라이언트의 연결 정보를 옮길 필요가 없어서 확장이 편하고,
    서버가 연결 유지를 담당하지 않기 때문에 자원이 Stateful에 비해 적게 들어간다.

Stateful한 서비스의 연결정보가 Server 1에 있다면, Server 2를 새로 신설하려고 할 때, Server 1의 사용자 연결 정보를 가져오거나, Server 2에서도 사용자 연결 정보를 새로 만들어야한다. 오버헤드라고 할 수 있다.

Stateful한 서비스는 사용자에 자원을 많이 사용하기 때문에, 사용자가 많으면 자원이 부족할 수 있다. Stateless는 Stateful에 비해 사용자에 쓰는 자원이 많지 않기 때문에, 많은 사용자를 감당 가능하다.
하지만, Stateless한 서비스는 Stateful한 서비스보다 주고받는 정보량 자체는 많다.


👀 JWT란?

JWT는 JSON Web Token이라는 뜻으로, JSON 문법으로 이루어진 웹 상 토큰이라는 뜻이다.

JWT는 클라이언트가 인증 요청을 할 시에 발급되어, 응답을 통해 전달되는 토큰이다.
추후에 클라이언트가 다시 요청을 할 때, 요청 헤더에 제시하면, 인증이 가능하다.

🔑 JWT의 구조

JWT의 구조는 이렇다.

큰 구조 = Message + Signature
작은(실제) 구조 = (Header + Payload) + Signature

JWT는 xxxx.yyyy.zzzz 처럼 생겼다.

📨 Message

  • Message 에는 서버가 보내야 하는, 보내고 싶은 정보가 담겨있다.
  • xxxx.yyyy 부분이 Message 이다.
  • Base64 로 암호화되어있어, 누구나 획득하기만 한다면, 복호화하여 정보를 볼 수 있다.
    • JWT에 중요한 정보를 넣으면 안된다는 것을 알 수 있다!!

🍖 Header

  • xxxx 부분이 Header이다.
  • Header 에는 암호화를 어떻게 하였는가, 이 토큰은 무슨 토큰인가, 등을 명시한다.
    • <alg> : 암호화를 어떻게 하였는가를 명시한다. 암호화에는 RS256, HS256 등이 있다.

      RS256은 sha256 + 비대칭키를 사용하는 암호화 방식이고,
      HS256은 sha256 + 대칭키를 사용하는 암호화 방식이다.

    • <typ> : Token의 Type을 명시한다. JWT 니까 당연 JWT라고 써있다.

🎈 Payload

PayloadHeader와 다르게 종류가 3개 있다.

  • Registered claims
    • <iss> : 토큰 발행자 (Issuer)
    • <sub> : 토큰 제목. (Subject)
    • <aud> : 토큰 대상자. (Audience)
    • <exp> : 토큰 만료시간. Unix Time으로 적는다. (Expiration Time)
    • <nbf> : 토큰이 활성되는 시간. 이 시간 이후에 토큰을 사용할 수 있다.
      이것 또한 Unix time이다. (Not Before)
    • <jti> : JWT의 고유 식별자이다. 다른 JWT와 다른 Unique한 값을 지녀야 한다.
  • Public claims
    • JWT를 사용하는 사람들에 의해 정의되는 Claim이다.
    • IANA JSON Web Token Registry에 정의된 Claim Name을 사용하거나 다른 사람들과의 충돌을 방지하기 위해, URI를 사용해야한다. (다른것도 가능은 하지만, URI를 사용한다.)
  • Private Claims
    • IANA JSON Web Token Registry에 정의되어 있지 않는 Claim Name이면 뭐든지 사용 가능하다. (즉, Registered Claim Name, 일반적으로 사용하는 Claim Name이 아니어야 한다.)
    • JWT 사용자와 생산자 상호 합의 하에 정해지는 claim이다. (전체는 아닌, 이해당사자(?) 간에.)

🔏 Signature

Signature는 데이터의 무결성을 입증하는데 사용한다.

데이터가 중간에 탈취되어, Payload나 Header가 변경되어도,
Signature 검증을 통해 변경되었다는 것을 알 수 있다.

생성방식

HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)

  1. Header를 Base64Url 방식으로 인코딩한다.
  2. Payload를 Base64Url 방식으로 인코딩한다.
  3. 인코딩한 문자열 두 개 가운데 .을 넣어서 하나의 문자열로 만든다.
  4. (3.)에서 생성한 문자열을 Header에 명시된 암호화 방식으로 암호화한다.

🔐 JWT 인증 과정

대칭 키의 경우

JWT eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

  1. 받은 JWT를 .으로 구분하여, Header, Payload, Signature로 분류한다.
    • Header : eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
    • Payload : eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ
    • Signature : SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
  2. 원래 알고있던 Key와, 받은 Header(Base64Url)와 Payload(Base64Url)로 Signature를 생성한다.
  3. 새로 만든 Signature를 Base64Url 방식으로 인코딩한다.
  4. 받은 Signature와 만든 Signature가 같은 지를 비교한다.

비대칭 키의 경우

JWT
eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0.JlX3gXGyClTBFciHhknWrjo7SKqyJ5iBO0n-3S2_I7cIgfaZAeRDJ3SQEbaPxVC7X8aqGCOM-pQOjZPKUJN8DMFrlHTOdqMs0TwQ2PRBmVAxXTSOZOoEhD4ZNCHohYoyfoDhJDP4Qye_FCqu6POJzg0Jcun4d3KW04QTiGxv2PkYqmB7nHxYuJdnqE3704hIS56pc_8q6AW0WIT0W-nIvwzaSbtBU9RgaC7ZpBD2LiNE265UBIFraMDF8IAFw9itZSUCTKg1Q-q27NwwBZNGYStMdIBDor2Bsq5ge51EkWajzZ7ALisVp-bskzUsqUf77ejqX_CBAqkNdH1Zebn93A

  1. 받은 JWT를 .으로 구분하여, Header, Payload, Signature로 분류한다.
    • Header : eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9
    • Payload : eyJzdWIiOiIxMjM0NTY3ODkwI ... IiwiYWRtaW4iOnRydWUsImlhdCI6MTUxNjIzOTAyMn0
    • Signature : JlX3gXGyClTBFciHhknWrjo ... IFraMDF8IAFw9itZSUCTKg1Q-q27NwwBZNGYStMdIBDor2Bsq5ge51EkWajzZ7ALisVp-bskzUsqUf77ejqX_CBAqkNdH1Zebn93A
  2. 발행자가 알고있는 Private Key를 통해, Signature 부분을 복호화한다.
  3. Payload와, Header 비교를 통해 무결성을 입증한다.

    비대칭 키의 경우, 암호화나, 복호화 사이트를 통해서는 확인해볼수 없었다.
    암호화/복호화 사이트 내에서는 암호화, 복호화 확인이 가능했으나, jwt.io에서 나온 Signature를 복호화 할 경우에 오류를 내거나, 다르게 복호화했다.


📖 참고문헌

JWT를 정의한 RFC 문서 https://tools.ietf.org/html/rfc7519#section-4.1
JWT를 소개한 문서 https://jwt.io/introduction/
JWT 디버거 https://jwt.io/#debugger-io

암호화/복호화 사이트
https://www.devglan.com/online-tools/rsa-encryption-decryption
https://8gwifi.org/RSAFunctionality?keysize=512

Base64 https://www.base64decode.org/

인증 과정 https://juneyr.dev/2019-06-10/spring-hmac

0개의 댓글