본문 바로가기
Backend/인증

[인증] JWT (개념 정리, 특징, 구성요소, 토큰 탈취)

by WooHey 2022. 10. 22.

JWT 란?

  • Json Web Token (이하 JWT 또는 Token 또는 access token) 은 개방형 표준이며, Json 객체를 사용해서 Token 자체에 정보를 저장하는 Web Token 이다.
  • JWT 속의 정보(데이터)는 디지털 서명을 통해 확인하고, HTTP 를 통해 JWT 을 전송하는 경우에는 Token 의 각 구성요소를 암호화하여 전송한다.
  • JWT 발급 및 갱신은 Server 단에서 이뤄지며 JWT 를 전달받은 Client 는 해당 Token 을 지속적으로 활용하여 Sever 에 인증을 하기 때문에 Server 의 인증 절차 및 부하를 최소화 한다.
  • JWT 는 3가지 구성요소로 이뤄져 있다. (각 요소별 구조 및 세부사항은 하단에서 확인)

장/단점

장점

  • 크기: Json 코드 언어로 생성된 Token 은 용량이 작기 때문에 두 Entity 사이에서 매우 빠르게 전달된다.
  • 제어: 접근 가능한 데이터, 권한 지속 시간, 로그인 시 수행 가능한 작업 등을 지정할 수 있다.
  • 확장성: 중앙 인증 서버, 저장소(DB 등)에 대한 의존성이 없기 때문에 수평 확장에 유리하다.
  • 용이성: Base 64 Safe Encoding 이기 때문에 URL, Cookie, Header 등 어떤 형태로도 사용 가능하다.
  • 웹, 모바일 어느 곳에서 사용 가능하다.
  • 인증 정보를 다른 곳에서도 사용 가능하다. (ex. OAuth)

단점

  • 단일 키: JWT 은 단일 키를 이용하기 때문에 Token 이 유출되면 Server 는 진짜 사용자를 구분할 수 없다.
  • 복잡성: 인증 방법이 복잡하기 때문에 인증 서버를 구현할 때 서명 알고리즘에 정통하지 않는다면 시스템을 위험에 빠지게 할 수 있다.
  • Payload 의 정보가 많아지면 네트워크 사용량이 증가한다.
  • 다른 사람이 Token 을 Decode 하면 Token 내부 정보를 확인할 수 있다.
    • 때문에 Token 자체에는 민감한 정보를 넣지 않아야 한다.
  • Token 을 탈취당할 경우에 대한 대처가 어렵다.
    • Token 을 Server 에서 관리하지 않기 때문에 Token 을 탈취당한 경우, 강제 로그아웃이 불가능하다.
    • Token 유효기간이 만료되기 전까지 Server 는 진짜 사용자와 Token 탈취다를 구분할 수 없다.
      • 이를 대비하기 위해 Token 의 유효기간을 짧게 가져가고 refresh token(인증 절차에서 상세히 설명) 을 통해 token 을 재발급 하는 방식으로 많이 사용한다.

구성 요소

Header

  • 일반적으로 쓰이는 암호화 알고리즘들은 SHA-2(HS256) 방식의 HMAC와 SHA-256(RS256) 방식의 RSA 서명이다. JWA(Json Web Algorithm) RFC 7518은 인가 및 암호화를 위해 더 많은 것을 도입하고 있다.
    alg:
{
 "alg" : "HS256",        // Signature 를 해싱하기 위한 알고리즘 정보를 가진다.
                             // Signature 생성을 위해 어느 알고리즘을 사용할지를 식별한다.
                            // HS256는 이 토큰이 HMAC-SHA256를 사용하여 서명됨을 의미한다.
 "typ" : "JWT"            // typ: 토큰의 타입을 나타내며, 보통 JWT 를 사용한다.
}

Payload

  • Payload 에는 일련의 클레임을 포함한다. JWT 사양은 토큰에 일반적으로 포함되는 표준 필드인 7개의 등록 클레임 이름(Registered Claim Names)을 정의한다.
  • Token의 사용 목적에 따라 사용자 지정 클레임 또한 일반적으로 포함됩니다.
  • 서버와 클라이언트가 주고받는, 시스템에서 실제로 사용될 정보에 대한 내용을 담고 있다.
  • JWT 가 기본적으로 갖고 있는 키워드가 존재하고 원한다면 추가할 수도 있다.

registered claim

  • 등록된 클레임은 토큰 정보를 표현하기 위해 이미 정해진 종류의 데이터로, 선택적으로 작성이 가능하다. (사용 권장)

public claim

  • 공개 클레임은 사용자 정의 클래임으로, 공개용 정보를 위해 사용. 충돌 방지를 위해 URI 포맷을 이용
  • https://www.iana.org 여기에 공용으로 미리 정의된 claim name 을 사용

private claim

  • Server 와 Client 사이에 임의로 지정한 정보를 저장
{
// registered claim
    "iss": "http://token.issuer.com",        // 토큰 발급자
    "sub": "test_user@test.com",            // 토큰의 주제(고유)
      "aud": "http://token.audience.com",        // 토큰 대상자
    "exp": 1652356540,        // 토큰 만료시간으로, numericDate(unix timestamp) 형식으로 되어있어야 함
    "nbf": 1652320540,        // 토큰이 활성화 되는 날짜
      "iat": 1652320540,        // 토큰을 발급한 시간      
    "jti": "id6098364921",    // 토큰 식별자(고유ID)

// public claim  
    "profile": "https://cloud.test.com/user/id602394",    // 미리 정의된 공개용 claim name
    "website": "https://website.test.com/"                // 미리 정의된 공개용 claim name

// private claim
      "userType": "user",            // Server 와 Client 사이에 정의된 claim name
     "token_type": "access"        // Server 와 Client 사이에 정의된 claim name
}

Signature

  • 토큰을 안전하게 확인한다. 서명은 Base64url 인코딩을 이용하여 헤더와 페이로드를 인코딩하고 이 둘을 점(.) 구분자로 함께 연결시킴으로써 계산된다.
  • Base64url 인코딩은 base64 와 비슷하지만 각기 다른 영숫자를 사용하며 패딩(padding)은 제외한다.
  • 해당 문자열은 그 뒤 헤더에 규정된 암호화 알고리즘(이번 경우에는 HMAC-SHA256)에 유입된다.
  • 서버에서 토큰이 유효한지 검증하기 위한 문자열이다.
  • Header + Payload + Secret Key 로 값을 생성하므로 데이터 변조 여부 판단이 가능하다.
  • Secret Key 는 노출되지 않도록 서버에서 잘 관리가 필요하다.
HMAC-SHA256(
    secret_key,                                    // 토큰을 생성하기 위한 비밀 키
      base64urlEncoding(header) + '.' +
      base64urlEncoding(payload)
)

Access token & Refresh token

JWT(이하 access token) 역시 탈취자에 의해 access token 이 탈취되면 탈취자가 API 를 호출할 수 있다는 단점이 존재한다.

Session 의 경우 Session 저장소에서 탈취한 Session ID 를 삭제하면 되지만, JWT 는 Server 에서 관리하지 않기 때문에 access token 이 탈취당할 경우 속수무책으로 당할 수 밖에 없다. 때문에 access token 이 탈취되어도 피해가 최소화 되도록 access token 의 유효시간을 짧게 가져가고 access token 을 재발급할 수 있는 Refresh token 을 도입하는 방법이 있다.

access token 유효기간을 짧게 가져간다면, 사용자는 짧은 기간동안만 Resource 에 접근이 가능하고, access token 이 만료되었을 경우 사용자는 새로 로그인 하여 access token 을 새로 발급받아야 하는 번거로움이 생기는데, 이때 access token 을 재발급할 수 있는 refresh token 을 도입하여 refresh token 유효기간동안 사용자가 매번 로그인 하는 과정을 생략할 수 있다.

Refresh token

refresh token 은 목적이 Access token(JWT) 을 재발급 하기 위함이며, Refresh token 자체에는 사용자 정보가 없다. 그리고 Server 의 저장소에 각 사용자별 refresh token 값이 있으므로 어떤 사용자의 refresh token 인지 판단하기 용이하다.

Access token 을 탈취당했을 때, Server 측에서는 저장소에 저장된 refresh token 정보를 삭제하면 Access token 이 만료된 후 access token 재발급을 받지 못하도록 막을 수 있다. 이렇게 하면 사용자 resource 에 접근할 수 없도록 로그아웃 처리를 할 수 있다.

Refresh token 저장 장소

refresh token 은 Server 에서 별도의 저장소에 보관하는 것이 좋다.

Server 의 경우, NoSQL 이나 기타 DB 에 저장할 수 있다.

Client 의 경우, 브라우저로 예를 들면 Cookie 나 local storage 등 다양한 곳이 있지만, http-only 속성이 부여된 Cookie 에 저장하는 것을 권장한다.

이유는 http-only 속성이 부여된 Cookie 는 javascript 환경에서 접근할 수 없기 때문에 XSS 나 CSRF 가 발생 하더라도 refresh token 이 누출되지 않는다. 일반 Cookie 나 브라우저의 local storage 는 javascript 로 자유롭게 접근할 수 있기 때문에 보안 측면에서는 권장하지 않는다.

Token 재발급 시나리오

  1. Client 는 최초에 ID & PW 를 통해 access token 및 refresh token 을 발급 받는다.
  2. Client 는 Server 로 부터 발급 받은 access token 으로 API 를 호출하여 resource 접근 또는 service 를 제공 받는다.
  3. Client 가 만료된 access token 을 통해 Server 로 API 호출 시, Server 는 token 만료 응답을 내려준다.
  4. Client 는 token 만료 응답을 받고 access token 을 재발급 받기 위해 1. 에서 발급 받은 access token 과 refresh token 을 Server 로 전송한다.
  5. Server 는 access token 에 담긴 사용자 정보와 refresh token 의 유효성을 체크한다
    5-1. refresh token 이 유효하다면 access token 을 새로 발급하여 응답한다.
    5-2. refresh token 이 유효하지 않는다면 Client 는 ID & PW 로 로그인을 통해 access token 및 refresh token 을 새로 발급 받아야 한다.
    5-3. access token 에 담긴 사용자와 전달 받은 refresh token 의 사용자가 일치하지 않는 경우에는 Server 는 저장소에 저장된 refresh token 을 폐기 후 ID & PW 로 로그인을 해야한다고 응답한다.

Token 탈취 이슈

Access token 의 탈취

access token 이 탈취자에 의해 탈취당했을 경우에 Server 는 탈취자와 진짜 사용자를 구분하기가 어렵다. 때문에 탈취자는 access token 의 유효기간 동안 Server 로 부터 API 를 호출 하거나 사용자 resource 에 접근이 가능하다. 이를 방지하기 위해 refresh token 을 도입하고 access token 의 유효기간을 짧게 가져간다.

Refresh token 의 탈취

refresh token 이 탈취자에 의해 탈취당했을 경우에는 탈취자가 refresh token 의 유효기간 만큼 다시 access token 을 재발급 받아 정상 사용자인 것 처럼 위장할 수 있다. 100% 완벽한 보안은 없기 때문에 Server 측의 검증 로직 강화가 필요하다.


참조

'Backend > 인증' 카테고리의 다른 글

[인증] OAuth 2.0 (개념 정리)  (1) 2022.10.22
[인증] 사용자 인증 방식 종류  (0) 2022.10.22