9.1 JWT 기본 이해

SummerToday·2024년 2월 28일
1
post-thumbnail
post-custom-banner

토큰 기반 인증

  • 대표적인 사용자 인증 방법에는 서버 기반 인증 / 토큰 기반 인증 존재.

  • 스프링 시큐리티는 기본적으로 제공하는 세션 기반인증을 사용하여 사용자마다 사용자의 정보를 담은 세션을 생성/저장하여 인증 한다.

  • 토큰 기반 인증은 토큰을 사용하여 인증하는 방법이다.

    토큰은 서버에서 클라이언트를 구분하기 위한 유일한 값이다.

  • 서버가 토큰을 생성하여 클라이언트에게 제공하고, 클라이언트가 서버에게 요청과 함께 이 토큰을 전송하여 유효한 사용자인지 확인할 수 있게 된다.


클라이언트 - 서버 토큰 인증 과정

출처 : https://velog.io/@yh20studio/%ED%86%A0%ED%81%B0-%EA%B8%B0%EB%B0%98-%EC%9D%B8%EC%A6%9D-%EC%8B%9C%EC%8A%A4%ED%85%9C-JWT


토큰 기반 인증 특징 3가지

  • 무상태성 ( Stateless )
    사용자의 인증 정보가 담긴 토큰은 서버가 아닌 클라이언트가 저장하게 되어, 서버의 자원을 낭비하지 않게 된다.
    즉, 기존 서버 기반 인증과 달리 사용자 인증 정보를 더이상 서버가 저장하거나 유지하지 않게되어 무상태로 효율적인 검증을 할 수 있게 된다.

  • 확장성
    무상태성을 갖게 되므로, 추후 서버를 확장할 때도 용이하다.
    예를 들어, 클라이언트가 가지고 있는 토큰 하나로 별도의 과정 없이 여러 서버에게 인증 요청을 보내어 서비스를 확장하는 등이 가능하다.

  • 무결성
    토큰을 발급한 이후에는 토큰 정보를 변경하는 행위는 할 수 없어, 무결성이 보장된다.
    만약, 토큰이 중간에 변경이 될 시 서버에서는 유효하지 않은 토큰으로 판단하게 된다.

JWT

JSON Web Token의 약자로 전자 서명 된 URL-safe (URL로 이용할 수있는 문자 만 구성된)의 JSON 형식의 토큰의 표준 규격이다. 발급 받은 JWT를 이용해 인증을 하기 위해서는 HTTP 요청 헤더 중 Authorization 키 값에 Bearer + JWT 토큰값을 넣어 보내야한다.

출처 : https://i.stack.imgur.com/2bu8O.png


  • JWT 구조
    JWT는 .을 기준으로 헤더(header), 내용(payload), 서명(signature)으로 이루어져 있다.

    출처 : http://www.opennaru.com/opennaru-blog/jwt-json-web-token/

    • 헤더 (Header)
      토큰의 타입(type)과 해싱 알고리즘(alg)을 지정하는 정보를 담는다.

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

      위 같은 경우에는 JWT 토큰, HS256 해싱 알고리즘을 사용한다는 내용이다.


    • 내용 (Payload)
      토큰과 관련된 정보를 담는다. 내용의 단위를 클레임(claim)이라 칭하며, 클레임은 키값의 한 쌍으로 구성되어 있다.
      클레임은 등록된 클레임(registered claim), 공개 클레임(public claim), 비공개 클레임(private claim)으로 나눌 수 있다.

      • 등록된 클레임
        다음과 같이 토큰에 대한 정보를 담는데 사용된다.

        • iss
          토큰 발급자 (issuer)

        • sub
          토큰 제목(subject)

        • aud
          토큰 대상자(audience)

        • exp
          토큰의 만료 시간(expiration). 시간은 NumericDate 형식으로 하며(예:1480849147370), 항상 현재 시간 이후로 설정한다.

        • nbf
          토큰의 활성 날짜와 비슷한 개념으로 nbf는 Not Before를 의미한다. NumericDate 형식으로 날짜를 지정하며, 이 날짜가 지나기 전까지는 토큰이 처리되지 않는다.

        • iat
          토큰이 발급된 시간으로 iat은 issued at을 의미한다.

        • jti
          JWT의 고유 식별자로서 주로 일회용 토큰에 사용한다.

      • 공개 클레임 (public claim)
        공개되어도 상관 없는 클레임을 의미한다. 충돌을 방지할 수 있는 이름을 가져야하며, 보통 클레임 이름을 URI로 짓는다.

      • 비공개 클레임 (private claim)
        공개되면 안되는 클레임을 의미하고, 클라이언트와 서버 간의 통신에 사용된다.

      • JWT 예시
      {
        "iss": "qlql7748@gmail.com",  // 등록된 클레임
        "iat": 1622370878,  // 등록된 클레임
        "exp": 1622372678,  // 등록된 클레임
        "https://inkyung.com/jwt_claims/is_admin": true,  // 공개 클레임
        "email": "qlql7748@gmail.com",  // 비공개 클레임
        "hello": "Hello"  // 비공개 클레임
       }
    • 서명 (signature)
      해당 토큰이 조작되었거나 변경되지 않았음을 확인하는 용도로 사용되며, 암호화 되어있다.
      헤더의 인코딩값과 내용의 인코딩값을 합친 후에 주어진 비밀키를 사용해 해시값을 생성해 서명으로 사용한다.

      • JWE, JWS, JWT 추가 설명

        • JWT
          JSON Web Token으로, claims 집합을 JWS나 JWS+JWE 구조로 인코딩된 JSON 객체로 표현한다. 기술적으로 "JWT"는 서명되지 않은 토큰을 의미하지만, 일반적으로 JWT는 JWS나 JWS+JWE를 의미한다.
          여기서 Cliam은 서명을 하거나 암호화하여 사용하는데, 디지털 서명을 하는 방식은 JWS(JSON Web Signature)방식이고 암호화 하는 방식은 JWE(JSON Web Encryption)다. 이러한 claim의 집합은 JSON 객체로 표현되어 전달되는데, 이를 JWT Claims Set이라 한다.

        • JWS — JSON Web Signature
          서버는 JWT를 JWS 체계로 서명해서 시그너처signature와 함께 클라이언트로 전송한다. 시그너처는 JWT에 포함된 권한claim이 위조되었거나 변경되지 않았다는 것을 보장한다. 즉, JWS를 통해 위변조를 확인할 수 있을 뿐 JWT는 근본적으로 암호화 되지않은 문자열plaintext이다. 따라서 JWT에 민감한 정보를 저장해서는 안 된다.

        • JWE — JSON Web Encryption
          반면에 JWE 체계에서는 내용이 서명없이 암호화된다. 보안은 당연히 암호화 방식이 좋지만, 클라이언트가 claim의 데이터를 사용하려면 디지털 서명 방식을 사용해야한다. 따라서 대부분 JWT라고 하면 JWS를 가리킨다.
          JWE는 JWT에 암호화를 통한 기밀성은 부여하지만, JWE를 JWS로 서명해서 담는 만큼의 보안성을 제공하지는 못한다.
          즉, 결국은 JWS+JWE를 사용하여 안전한 토큰을 만들 수 있다.

JWT Process

출처 : http://www.opennaru.com/opennaru-blog/jwt-json-web-token/

  1. 클라이언트가 id와 password를 입력하여 로그인을 시도한다.

  2. 서버는 아이디와 비밀번호를 확인하여 유효한 사용자인지 검증 후, 유효한 사용자라면 secret key를 통해 Access token을 발급한다.

  3. JWT 토큰을 클라이언트에 전달하고, 클라이언트는 토큰을 저장한다.

  4. 클라이언트에서 인증이 필요한 API 을 요청할때 클라이언트가 Authorization header에 Access token을 담아서 함께 보낸다.

  5. 서버는 JWT 서명(signature)을 체크하고, 내용(payload)으로부터 사용자 정보를 확인해, 유효한 사용자인지 검증한다.

  6. 유효한 사용자라면, 클라이언트에게 요청한 내용을 전달한다.

cf. 클라이언트의 로그인 정보를 서버 메모리에 저장하지 않기 때문에 토큰기반 인증 메커니즘을 제공할 수 있다.


Refresh Token

보안성을 위해 토큰의 유효기간이 짧아야 좋지만, 사용자는 토큰을 너무 짧은 시간동안만 사용할 수 있어 불편할 수 있다. 이 부분을 보완하기 위해 나타난 개념이 리프레시 토큰이다.
리프레시 토큰은 사용자를 인증하기 위한 수단이 아니라, 액세스 토큰이 만료 되었을 시 새로운 엑세스 토큰을 발급하기 위해 사용되는 토큰이다.
따라서 액세스 토큰의 유효기간은 짧게 설정하고, 리프레시 토큰의 유효기간은 길게 설정하여 사용한다.

  • Refresh Token Process

    출처 : https://nowgnas.github.io/posts/refreshtoken/

    1. 클라이언트가 서버에게 인증 요청을 한다.

    2. 서버는 클라이언트에서 전달한 정보를 바탕으로 인증 정보가 유효한지 확인한 후, 엑세스 토큰과 리프레시 토큰을 만들어 클라이언트에게 전달한다. 클라이언트는 전달 받은 토큰을 저장한다.

    3. 서버에서 생성한 리프레시 토큰은 DB에도 저장한다.

    4. 인증을 필요로 하는 API를 호출할 때, 클라이언트는 저장된 액세스 토큰과 함께 API를 요청한다.

    5. 서버는 전달 받은 액세스 토큰을 검증한 후, 유효하다면 클라이언트에게 요청한 내용을 처리한다.

    6. 액세스 토큰이 만료된 뒤, 클라이언트가 만료된 엑세스 토큰과 함께 API를 요청한다.

    7. 서버는 전달 받은 엑세스 토큰을 검증한 후, 만료되었다면 토큰이 만료되었다는 에러를 클라이언트에게 응답한다.

    8. 클라이언트는 저장해둔 리프레시 토큰과 함께 새로운 엑세스 토큰을 발급하는 요청을 서버에게 보낸다.

    9. 서버는 전달 받은 리프레시 토큰을 DB에 저장되어 있는 리프레시 토큰과 같은지 확인한다.

    10. 만약 유효한 리프레시 토큰이라면, 새로운 엑세스 토큰을 재발급하여 클라이언트에게 응답해준다.
      그 이후 클라이언트는 다시 API 요청을 하게된다.




해당 글은 다음 도서의 내용을 정리하고 참고한 글임을 밝힙니다.
신선영, ⌜스프링 부트 3 벡엔드 개발자 되기 - 자바 편⌟, 골든래빗(주), 2023, 384쪽

추가 참고
http://www.opennaru.com/opennaru-blog/jwt-json-web-token/
https://medium.com/@OutOfBedlam/jwt-%EC%9E%90%EB%B0%94-%EA%B0%80%EC%9D%B4%EB%93%9C-53ccd7b2ba10
https://velog.io/@dae-hwa/JWTJSON-Web-Token-%EC%95%8C%EC%95%84%EB%B3%B4%EA%B8%B0

profile
IT, 개발 관련 정보들을 기록하는 장소입니다.
post-custom-banner

0개의 댓글