인증 알아보기 (비밀번호, 세션, 쿠키, 토큰, JWT, SSO, OAuth)

원문: https://blog.bytebytego.com/p/password-session-cookie-token-jwt



우리가 다양한 애플리케이션과 웹사이트를 사용할 때, 세 가지 핵심 보안 단계가 지속적으로 동작합니다

  • 신원

  • 인증

  • 권한 부여

아래 다이어그램은 위 단계들이 전형적인 웹사이트 구조에서 어디에 적용되는지와 그 의미를 나타냅니다.


이 글에서는 비밀번호, 세션, 쿠키, 토큰, JWT(JSON 웹 토큰), SSO(싱글 사인온), OAuth2를 포함한 다양한 인증 방법에 대해 살펴봅니다. 각 방법이 해결하는 문제와 우리의 요구에 맞는 올바른 인증 방법을 선택하는 방법에 대해 논의합니다.

비밀번호 인증

비밀번호 인증은 웹사이트와 애플리케이션에서 사용자의 신원을 확인하는 기본적이고 널리 사용되는 메커니즘입니다. 이 방법에서 사용자는 고유한 사용자 이름과 비밀번호 조합을 입력하여 보호된 자원에 접근할 수 있습니다. 입력된 자격증명은 시스템에 저장된 사용자 정보와 비교되며, 일치하면 사용자에게 접근 권한이 부여됩니다.

비밀번호 인증은 사용자 확인의 기본적인 방법이지만 일부 한계가 있습니다. 사용자는 비밀번호를 잊어버릴 수 있으며, 여러 웹사이트에 대해 고유한 사용자 이름과 비밀번호를 관리하는 것이 어려울 수 있습니다. 게다가, 적절한 보안 조치가 없으면 비밀번호 기반 시스템은 무차별 대입 공격이나 사전 공격과 같은 공격에 당할 수 있습니다.

이러한 문제를 해결하기 위해 현대 시스템은 종종 다중 인증 요소를 사용하거나, 세션-쿠키 또는 토큰 기반 인증과 같은 다른 인증 메커니즘을 사용하여 비밀번호 기반 인증을 보완하거나 대체합니다.

이 섹션에서는 비밀번호 기반 인증을 먼저 봅니다.

HTTP 기본 액세스 인증

HTTP 기본 액세스 인증은 로그인을 요청할 때 웹 브라우저에 사용자 이름과 비밀번호를 제공하도록 요구합니다. 자격 증명은 Base64 알고리즘을 사용하여 인코딩되고, HTTP 헤더 필드 Authorization: Basic에 포함됩니다.

일반적으로 다음과 같이 작동합니다

1. 클라이언트는 서버의 보호된 리소스에 액세스하기 위해 요청을 보냅니다.

2. 클라이언트가 아직 인증 자격 증명을 제공하지 않은 경우, 서버는 401 Unauthorized 상태 코드를 응답하고, 기본 인증이 필요하다는 것을 나타내기 위해 WWW-Authenticate: Basic 헤더를 포함합니다.

3. 그런 다음 클라이언트는 사용자에게 사용자 이름과 비밀번호를 입력하도록 요청하고, 이를 username:password 형식의 단일 문자열로 결합합니다.

4. 결합된 문자열은 Base64 인코딩되어 이후 서버로의 요청에서 "Authorization: Basic" 헤더에 포함됩니다. 예를 들어, Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=.

5. 요청을 받은 서버는 Base64로 인코딩된 자격 증명을 디코딩하고 사용자 이름과 비밀번호를 분리합니다. 그런 다음 서버는 제공된 자격 증명을 사용자 데이터베이스 또는 인증 서비스와 비교합니다.

6. 자격 증명이 일치하면 서버는 요청된 리소스에 대한 액세스를 허용합니다. 그렇지 않으면 서버는 401 Unauthorized 상태 코드를 응답합니다.

HTTP 기본 액세스 인증에는 한계가 있습니다. Base64로 인코딩된 사용자 이름과 비밀번호는 쉽게 디코딩될 수 있습니다. 대부분의 웹 사이트는 TLS(Transport Layer Security)를 사용하여 브라우저와 서버 간의 데이터를 암호화하여 보안을 개선합니다. 그러나 사용자의 자격 증명은 여전히 도청 또는 중간자 공격에 노출될 수 있습니다.

HTTP 기본 액세스 인증을 사용하면, 브라우저는 같은 도메인 내 보호된 리소스에 대한 각 요청에 필요한 자격 증명이 있는 Authorization 헤더를 전송합니다. 이로 인해 사용자는 사용자 이름과 비밀번호를 반복해서 입력하지 않고 원활한 사용자 경험이 제공됩니다. 그러나 각 웹사이트가 고유한 사용자 이름과 비밀번호를 유지하기 때문에 사용자는 자격 증명을 기억하기 어려울 수 있습니다.

이 인증 메커니즘은 현대 웹사이트에는 적합하지 않습니다.

세션-쿠키 인증

세션-쿠키 인증은 HTTP 기본 액세스 인증이 사용자 로그인 상태를 추적할 수 없는 문제를 해결합니다. 사용자의 상태를 추적하기 위해 세션 ID가 생성됩니다. 이 세션 ID는 서버 측과 클라이언트의 쿠키에 모두 기록되어 인증 메커니즘 역할을 합니다. 세션 ID가 저장된 쿠키이기 때문에 세션-쿠키라고 불립니다. 사용자는 처음에 사용자 이름과 비밀번호를 제공해야 하며, 그 후 서버는 사용자 방문을 위한 세션을 생성합니다. 이후 요청에는 쿠키가 포함되어 있어 서버가 클라이언트 측과 서버 측의 세션 ID를 비교할 수 있습니다.

작동 방식을 살펴보겠습니다

  1. 클라이언트는 서버의 보호된 리소스에 액세스하기 위한 요청을 보냅니다. 클라이언트가 아직 인증되지 않은 경우, 서버는 로그인 프롬프트로 응답합니다. 클라이언트는 사용자 이름과 비밀번호를 서버에 제출합니다.

  2. 서버는 제공된 자격 증명을 사용자 데이터베이스 또는 인증 서비스와 대조하여 확인합니다. 자격 증명이 일치하면 서버는 고유한 세션 ID를 생성하고 서버 측 저장소(예: 서버 메모리, 데이터베이스, 세션 서버)에 해당 세션을 생성합니다.

  3. 서버는 Set-Cookie 헤더를 사용하여 일반적으로 세션 ID를 쿠키로 클라이언트에게 전송합니다.

  4. 클라이언트는 세션 쿠키를 저장합니다.

  5. 이후 요청에서는 쿠키를 요청 헤더와 함께 전송합니다.

  6. 서버는 쿠키의 세션 ID를 저장된 세션 데이터와 대조하여 사용자를 인증합니다.

  7. 유효성이 검증되면 서버는 요청된 리소스에 대한 액세스를 허용합니다. 사용자가 로그아웃하거나 미리 정해진 만료 시간이 지나면 서버는 세션을 무효화하고 클라이언트는 세션 쿠키를 삭제합니다.

세션 정보는 서버 메모리나 독립적인 세션 서버에 저장될 수 있으며, 이는 시스템의 확장성과 신뢰성 요구 사항에 따라 다릅니다. 서버 메모리에 세션을 저장하면 상당한 리소스가 소모되어 서버 성능에 영향을 줄 수 있습니다. 때문에 시스템 지표를 주의 깊게 모니터링해야 합니다.

세션-쿠키 인증에는 일부 제한 사항이 있습니다.

세션 쿠키는 세션 하이재킹 공격에 취약할 수 있습니다. 공격자가 세션 쿠키를 훔치고 사용자를 가장하여 사용할 수 있습니다. 이는 세션 쿠키가 보안되지 않은 네트워크를 통해 전송되거나 웹사이트가 크로스 사이트 스크립팅(XSS) 공격에 취약한 경우 발생할 수 있습니다.

세션 쿠키는 크로스 사이트 요청 위조(CSRF) 공격에 노출될 수 있습니다. 이는 해커들이 사용자의 브라우저를 속여 웹사이트에서 알지 못하는 행동을 실행하게 합니다. 해커들은 대상 사이트로의 링크가 포함된 악의적인 사이트나 이메일을 만듭니다. 사용자가 링크를 클릭하면 브라우저가 세션 쿠키와 함께 요청을 전송하여 사이트가 진짜 사용자 요청이라고 생각하게 만듭니다. CSRF 공격에 대응하기 위해 웹사이트는 안티-CSRF 토큰을 사용하거나 민감한 작업에 대해 재인증을 요구할 수 있습니다.

세션 쿠키는 각 세션에 대해 서버 측 세션 상태를 저장해야 하므로 사용자 수가 많아질수록 확장하기 어려울 수 있습니다. 사용자 수와 세션 수가 증가함에 따라 성능 병목 현상이 발생할 수 있습니다.

세션 쿠키는 모바일 네이티브 애플리케이션에서 웹 애플리케이션에 비해 사용하기 덜 편리합니다. 안드로이드와 iOS 플랫폼은 쿠키를 처리하기 위한 API를 제공하지만 웹 기반 애플리케이션보다 프로세스가 더 복잡합니다. 웹 브라우저는 쿠키를 자동으로 관리하여 개발자의 작업을 단순화합니다. 반면에 네이티브 모바일 앱 개발자들은 사용 가능한 API를 사용하여 쿠키를 직접 관리해야 하므로 개발 복잡성이 증가합니다.

토큰 기반 인증

토큰 기반 인증은 웹 애플리케이션과 네이티브 모바일 앱에서 사용자 액세스를 보호하기 위한 현대적인 접근 방식입니다. 이는 세션-쿠키 인증의 일부 제한 사항을 해결하고 무상태 서버 측 처리 및 다양한 플랫폼과의 더 나은 호환성과 같은 이점을 제공합니다.

기본 토큰 인증

토큰 기반 인증은 세션-쿠키 인증의 한계를 해결합니다. 서버는 세션을 생성하는 대신 토큰을 발행하고 클라이언트에게 전송합니다. 클라이언트는 로컬 저장소에 토큰을 저장합니다. 이후 요청은 토큰을 HTTP 헤더에 포함시켜 유효성 검사를 수행하고, 사용자가 지정된 기간 동안 보호된 리소스에 액세스할 수 있게 합니다.

기본 토큰 인증에서 클라이언트-서버 상호 작용은 일반적으로 다음 단계를 따릅니다:

  1. 클라이언트는 서버의 보호된 리소스에 액세스하는 요청을 보냅니다. 클라이언트가 아직 인증되지 않은 경우, 서버는 로그인 프롬프트로 응답합니다. 클라이언트는 사용자 이름과 비밀번호를 서버에 제출합니다.

  2. 서버는 제공된 자격 증명을 검증하고 유효한 경우 고유한 토큰을 발행합니다.

  3. 토큰이 클라이언트에게 다시 전송됩니다.

  4. 클라이언트는 로컬 저장소에 토큰을 저장합니다.

  5. 이후 요청에는 HTTP 헤더에 토큰이 포함됩니다.

  6. 서버는 받은 토큰을 검증합니다.

  7. 서버는 요청된 리소스에 대한 액세스 권한을 부여합니다.

세션 인증과 토큰 인증 사이의 차이점은 다음과 같습니다:

  • 토큰 기반 인증은 쿠키에 의존하지 않으므로 쿠키가 제한될 때 지원될 수 있습니다. 이는 모바일 네이티브 앱뿐만 아니라 웹 애플리케이션에서도 사용할 수 있으며, 쿠키 기반 인증의 한계를 완화할 수 있습니다. 이에는 동일한 제한이 적용되지 않은 토큰 때문에 크로스 도메인 액세스 및 CSRF 공격이 포함됩니다.

  • 토큰에는 일반적으로 사용자 ID가 포함되어 있으며, 각 요청에 함께 전송되어 서버에서 토큰 정보를 메모리에 저장할 필요를 없앱니다. 이 때문에 토큰 기반 인증을 무상태 인증이라고도 합니다.


기본 토큰 인증의 한 가지 제한 사항은 토큰이 안전하지 않은 연결을 통해 전송될 경우 도난에취약할 수 있다는 것입니다. 기본 토큰에는 만료 또는 취소 기능이 내장되어 있지 않을 수 있으며, 토큰이 탈취당할 경우 보안 위험이 발생할 수 있습니다.
고품질 토큰 구현은 보안 기능이 강화되어 있습니다. 많은 애플리케이션은 주기적인 토큰 갱신을 요구하며, 일부는 계층화된 토큰 관리를 제공합니다.

예를 들어 Stripe의 API 키 관리 접근 방식은 세 가지 보안 수준을 포함합니다:

발행 가능한 키(Publishable key): 읽기 전용 메트릭을 표시하는 것과 같은 공개적인 웹 사이트에서 사용하도록 설계되었습니다.

비밀 키(Secret key): 모든 요청을 수행할 수 있는 이 키는 기밀로 유지되어야 합니다. 예를 들어, 계좌 잔액을 확인하는 데 사용할 수 있습니다.

제한된 키(Restricted key): 다양한 API 호출에 대한 더 세밀한 제어를 제공합니다. 예를 들어, 제한된 키는 결제 수단에 대한 읽기 및 쓰기 액세스를 허용하면서 요금 액세스를 읽기 전용으로 제한할 수 있습니다.


보안을 강화하기 위해 키를 교체하여 효과적으로 새로 고칠 수 있습니다.

JWT (JSON 웹 토큰)

JWT는 토큰 자체 내에 추가 정보를 포함함으로써 토큰 기반 인증에 대한 더 강력한 솔루션을 제공합니다. JWT는 토큰 생성 및 검증을 위한 표준화된 형식을 제공하여 전반적인 보안을 개선하고 서버 측 조회의 필요성을 줄입니다.

JWT는 인증과 정보 교환 모두에 유용합니다. 클라이언트와 서버 간의 보다 효율적인 통신을 가능하게 합니다. 사용자 역할 및 권한과 같은 클레임을 포함할 수 있으며, 이를 통해 인가 과정을 간소화할 수 있습니다. 이러한 추가 기능은 서버 측 조회의 필요성을 줄여 성능을 향상시키고 서버 부하를 줄입니다.


JWT 인증에서 클라이언트-서버 상호 작용은 일반적으로 다음 단계를 따릅니다:

  1. 클라이언트는 서버에서 보호된 리소스에 액세스하려는 요청을 보냅니다.

  2. 클라이언트가 아직 인증되지 않은 경우, 서버는 로그인 프롬프트로 응답합니다.

  3. 클라이언트는 사용자 이름과 비밀번호를 서버에 제출합니다.

  4. 서버는 제공된 자격 증명을 확인하고 유효한 경우 JWT를 클라이언트에 발급합니다.

  5. 클라이언트는 JWT를 로컬 스토리지에 저장하고 후속 요청에 대한 HTTP 헤더에 포함시킵니다.

  6. 서버는 JWT를 검증하고 요청된 리소스에 대한 액세스 권한을 부여합니다.

JWT 토큰은 세 부분으로 구성됩니다:

헤더: 토큰 유형(typ)과 해시 알고리즘(alg)을 포함합니다. 예를 들어 HMAC SHA256 또는 RSA와 같은 것들입니다.

페이로드: 7개의 사전 정의된 클레임(필수는 아니지만 권장됨), 공개 클레임 및 개인 클레임이 포함됩니다.

서명: 인코딩된 헤더, 인코딩된 페이로드 및 비밀로 생성됩니다.

JWT의 한 가지 제한 사항은 크기 관련 문제에 대한 가능성입니다. 페이로드에 너무 많은 정보가 포함되어 있으면 토큰 크기가 증가하여 성능 문제와 대역폭 사용량이 증가할 수 있습니다. 또한, 약한 서명 키의 사용이나 안전하지 않은 연결을 통한 전송과 같이 적절하게 보안되지 않으면 JWT는 공격에 취약할 수 있습니다.