JWT OAuth2.0 구조와 흐름

agnusdei·2023년 8월 10일
0

Bearer 토큰은 인증 및 권한 부여를 위해 사용되는 토큰 형식 중 하나로, HTTP 요청의 헤더에 포함되어 서버에게 인증 정보를 전달합니다. 보통 OAuth 2.0 프로토콜을 따르는 인증 시스템에서 사용되며, 다양한 웹 및 API 서비스에서 보안을 위해 사용됩니다.

Bearer 토큰의 구조는 다음과 같습니다:

Bearer <access_token>
  • Bearer: 토큰 종류를 나타내는 문자열로, "Bearer"라는 단어가 고정적으로 사용됩니다.
  • <access_token>: 실제로 사용자 또는 클라이언트의 인증 정보를 나타내는 문자열입니다. 이 부분에는 액세스 토큰 또는 토큰 문자열이 들어갑니다.

여기에 예시를 들어 설명하면, 아래와 같은 헤더가 HTTP 요청에 사용될 수 있습니다:

Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

실제로 <access_token> 부분에는 인증 시스템에서 발급한 사용자 또는 클라이언트의 액세스 토큰이 들어갑니다. 이 액세스 토큰은 일반적으로 디코딩해보면 토큰에 대한 정보, 유효 기간 및 기타 메타데이터를 포함하고 있습니다. 클라이언트가 서버에 요청을 보낼 때 이러한 Bearer 토큰을 함께 전달하여 인증을 수행하게 됩니다.

이러한 Bearer 토큰 구조는 보안을 강화하고 사용자나 클라이언트의 인증 정보를 안전하게 전달하기 위해 사용됩니다.

Bearer 토큰의 구조에서 점(.)으로 구분된 총 3개의 섹션은 JWT (JSON Web Token) 형식을 나타냅니다. JWT는 액세스 토큰을 포함하여 정보를 안전하게 전달하기 위한 인코딩된 데이터 형식입니다. 이 섹션들은 Base64 인코딩된 문자열로 구성되며, 각각의 섹션은 다음과 같은 역할을 수행합니다:

  1. Header (헤더): 첫 번째 섹션은 JWT의 헤더입니다. 헤더는 토큰의 타입 및 사용하는 해시 알고리즘을 지정하는 데 사용됩니다. 헤더는 JSON 객체로 표현되며, 일반적으로 다음과 같은 정보를 담고 있습니다:

    {
      "alg": "HS256", // 암호화 알고리즘
      "typ": "JWT"    // 토큰 타입
    }
  2. Payload (페이로드): 두 번째 섹션은 페이로드입니다. 페이로드는 토큰에 포함될 데이터를 담고 있는 부분으로, 클레임(Claim) 정보를 포함할 수 있습니다. 클레임은 토큰에 대한 메타데이터나 사용자 정의 데이터를 나타내며, 다음과 같은 구조를 가질 수 있습니다:

    {
      "sub": "1234567890", // 주제(Subject)
      "name": "John Doe",
      "iat": 1516239022    // 토큰 발급 시간(Issued At)
    }
  3. Signature (서명): 세 번째 섹션은 서명입니다. 서명은 헤더와 페이로드를 조합한 후, 비밀 키를 사용하여 생성된 서명값입니다. 서명은 토큰의 무결성을 검증하는 데 사용됩니다. 서명은 다음과 같이 표현됩니다:

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

    여기서 HMACSHA256는 해시 알고리즘이고, base64UrlEncode는 Base64 URL 인코딩을 나타냅니다.

이러한 3개의 섹션을 합치면 하나의 JWT 토큰이 생성됩니다. 예를 들어, 헤더와 페이로드가 JSON 객체로 주어졌을 때, 실제 JWT 토큰은 다음과 같이 구성됩니다:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c

이 토큰은 Base64 인코딩 및 서명으로 구성되어 있으며, 클라이언트가 서버에 토큰을 제출할 때 사용되어 인증 및 권한 부여를 수행합니다.

서명(Signature)은 데이터의 무결성과 신원을 보장하기 위한 과정으로, 디지털 서명의 일부로 사용됩니다. 서명은 비밀 키를 사용하여 데이터를 암호화하는 과정입니다. 데이터가 서명되면 데이터에 대한 변경 여부와 서명자의 신원을 확인할 수 있게 됩니다.

JWT(JSON Web Token)의 서명 과정은 다음과 같이 이루어집니다:

  1. 헤더와 페이로드 생성: JWT 토큰은 헤더와 페이로드가 합쳐진 형태로 서명됩니다. 먼저, 헤더와 페이로드를 JSON 형식으로 생성합니다.

  2. 서명 생성: 서명은 헤더와 페이로드를 비밀 키로 암호화하여 생성됩니다. 일반적으로 HMAC(Hash-based Message Authentication Code) 알고리즘 또는 RSA(암호화 및 전자 서명 알고리즘)와 같은 암호화 기법이 사용됩니다. HMAC은 공유 비밀 키를 사용하여 메시지와 키를 조합하여 해시 값을 생성하는 기법입니다.

  3. JWT 생성: 헤더, 페이로드 및 서명을 조합하여 하나의 JWT 토큰을 생성합니다. 각 섹션은 점(.)으로 구분됩니다.

  4. 클라이언트 요청: 클라이언트가 JWT 토큰을 생성하고, HTTP 요청의 헤더에 토큰을 포함하여 서버에 요청을 보냅니다.

  5. 서버 검증: 서버는 받은 JWT 토큰을 디코딩하여 헤더와 페이로드를 확인합니다. 그런 다음, 저장된 비밀 키를 사용하여 클라이언트의 서명과 일치하는지 확인합니다. 서명이 일치하지 않거나 토큰이 변조되었다면 검증은 실패합니다.

이렇게 JWT 서명을 통해 클라이언트와 서버 간의 통신에서 데이터의 무결성과 신원을 보장할 수 있습니다. 클라이언트는 비밀 키를 갖고 있지 않으므로 서명된 JWT 토큰의 변조가 어렵습니다. 따라서 서버는 토큰의 유효성을 검증하여 안전한 통신을 확보할 수 있습니다.

예시:

const jwt = require('jsonwebtoken');

// 헤더와 페이로드 생성
const header = { alg: 'HS256', typ: 'JWT' };
const payload = { userId: '123456', name: 'John Doe' };

// 비밀 키로 서명 생성
const secretKey = 'your-secret-key';
const signature = jwt.sign(payload, secretKey, { header });

// JWT 생성 (헤더, 페이로드, 서명 조합)
const jwtToken = `${base64UrlEncode(header)}.${base64UrlEncode(payload)}.${signature}`;

// 클라이언트 요청으로 서버에 JWT 전송
// ...

// 서버에서 JWT 검증
const receivedJwt = '...'; // 클라이언트에서 받은 JWT 토큰
const decoded = jwt.verify(receivedJwt, secretKey);
console.log(decoded); // 토큰이 유효한 경우, 디코딩된 페이로드 출력

위의 예시에서 jwt.sign() 메서드는 헤더와 페이로드를 서명하여 JWT 토큰을 생성합니다. jwt.verify() 메서드는 받은 JWT 토큰의 유효성을 검증하고, 디코딩된 페이로드를 반환합니다.

jsonwebtoken 라이브러리의 verify 함수는 다재다능하며, 다음과 같은 역할을 수행합니다:

  1. 시그니처 검사 (Signature Verification): verify 함수는 비밀 키를 사용하여 토큰의 서명을 확인합니다. 이를 통해 토큰이 변조되지 않았는지 확인하며, 토큰의 무결성을 검증합니다.

  2. 토큰의 만료 검사 (Expiration Check): verify 함수는 토큰의 만료 시간을 확인하여 토큰이 유효한 기간 내에 생성되었는지 검사합니다. exp(만료 시간) 클레임이 있는 경우, 이 값을 기준으로 현재 시간과 비교하여 토큰이 만료되었는지 확인합니다.

  3. 엑세스 토큰의 유효성 검사: verify 함수는 토큰의 발급자(iss 클레임)나 대상 사용자(sub 클레임) 등을 검사하여 토큰이 올바른 사용자에 의해 생성된 것인지 확인할 수 있습니다.

  4. 클레임 검증 (Claims Verification): verify 함수는 클레임에 대한 추가적인 검증을 수행할 수 있습니다. 예를 들어, 사용자 역할(role 클레임)이나 사용자 권한(permissions 클레임) 등을 확인하여 접근 제어를 강화할 수 있습니다.

이와 같은 다양한 기능으로 verify 함수는 JWT 토큰의 무결성, 유효성 및 신뢰성을 검증하며, 인증과 권한 부여 프로세스에서 중요한 역할을 합니다. 프로덕션 환경에서는 이러한 검사를 통해 보안을 강화하고 안전한 인증 시스템을 구축할 수 있습니다.

0개의 댓글