인증 알아보기 (비밀번호, 세션, 쿠키, 토큰, 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는 공격에 취약할 수 있습니다.

2022년 회고와 2023년 시작

2022 나의 삶에 대한 회고

회고의 목적은 2022년 내가 무얼 잘했고, 또 못했고. 2023년은 뭘 어떻게 해야하는지 정리하기 위해서이다.

2022년은 업스테이지를 열심히 다녔고, 결혼을 했고, 처음으로 부모님 집을 떠나 새 집에서 살게 되었고, 취미로 사진도 찍으며 현상, 스캔도 하고, 테니스도 시작한 해다. 

하나씩 어떻게 했고 어떻게 할건지 보자.

커리어

업스테이지는 앞선 글에도 적긴했지만 열심히 달리는 중이다. 이제 2년된 신생회사니 다들 열심히 시도하고 실패하고 다시하는 중. 나도 업스테이지에서 아주 만족도가 높다. 2022년은 사내 딥러닝 모델 학습 플랫폼을 만들고 고도화하고 1.0을 위해 열심히 개발했다. 이 과정에서 내가만든 플랫폼을 팔기도 했는데, MLops 플랫폼을 개발하고 팔아보는건 내가 업스테이지에 오기전부터 하고 싶었던 것. 하지만 애초에 사내 플랫폼으로만 생각하고 만들어서 그런지 팔아보는 과정은 생각보다 쉽지 않았고 내가 생각했던 형태도 아니었긴 하다. 솔루션 형태로 제공하게 되면서 부족한 기능을 업데이트 하기도 쉽지 않고 업체측에 설치, 운영 노하우를 전달하는 것도 쉽지 않았다. 지속적으로 하긴 어려운 느낌. 이런 형태로는 돈벌기가 쉽지 않다는 것을 깨달은 한 해였고, 다음에는 SaaS 형태도 경험해 볼 수 있으면 좋겠다는 생각. 이번에 예상치 못한 형태로 제품을 팔아보면서 일은 어떻게 될 지 모르니 애초에 여러 형태로 팔 수 있도록 설계해야한다는 생각도 든다.

내 커리어에는 많은 변화가 생겼다. 업스테이지에 오기전엔 소프트웨어 개발, 배포만 해왔고 여기서도 그것만 할거라고 생각했는데 큰 오산이었다. 실제로는 인프라의 많은 부분을 만지고 있다. 노드 세팅, 각종 드라이버, 환경 세팅, 디버깅 수준의 레벨과 간단한 수준의 aws 시스템 구성, 쿠버네티스 클러스터 구성, 운영같은 devops 에 더 가까운 업무를 많이 했다. 개인적으로는 리눅스도 많이 다루고 지식이 부족한 네트워킹 쪽을 좀 더 보고 공부하게 되면서 얻은 부분도 많다. 그리고 쿠버네티스 클러스터를 구성하고 운영하는게 얼마나 리소스가 들어가는지 까지. Devops 업무들이 앞으로도 나한테 많이 도움이 될 듯하고 플랫폼 엔지니어링에도 많이 필요한 부분이라 앞으로도 어느 정도는 쭉 가져가는게 좋다고 생각한다. 물론 인프라를 만지는 정도까지는 아니고 IaC를 하는 수준으로다.

2023년에는 플랫폼을 MLops 플랫폼으로 업그레이드하는 업무와 devops 업무가 계속갈 듯 하다. 지금까지는 모델을 연구하고 학습하는 것이 플랫폼의 주요 기능이었다면 앞으로는 자동화, 서빙이 중요해질 듯 하고 이걸 공통 플랫폼으로 어떻게 만들지가 중요하다. 이 기능을 만들면서 모델러와 실제 파이프라인을 만들며 자동화 파이프라인을 만들어보고, 올해 안에 플랫폼 1.0이 나오지 않을까? 

1.0이 나오고 난 후에는 뭘 해야할까? 우리팀은 업스테이지가 현재 가장 집중하는 곳에 기능을 만들고 있다. 작년엔 기술력을 쌓기 위한 학습 플랫폼을 만들었고 올해는 제품을 만들기 위한 자동화 파이프라인, 서빙을 만들 것이다. 그 뒤는 업스테이지 ai 팩이 어떤 성과를 보여주느냐에 방향이 달려 있다.

그러면 올해 커리어 측면에서 나에게 중요한 것을 무엇일까? 내부 플랫폼을 탄탄히 설계, 구현하는 것은 당연하고 이제 프로덕션이 나오는 시기인 만큼 프로덕션 레벨의 클러스터 구성, 복잡하고 대용량 트래픽을 고려한 서비스 설계가 될 거 같다. 모니터링, 로깅 같은 부분도 현재는 간단하게만 되어있는데 이걸 프로덕션 수준으로 끌어올려야 한다. 한마디로 서비스의 모든 수준을 한단계 향상시키는 것. 내부에서만 쓰던 것에서 외부에서도 쓰는 것으로 향상이다.

소프트 스킬로 향상시키고 싶은 부분은 구조화되고 이해하기 쉬운 문서 작성, 그리고 발표 능력이다. 발표 능력이 그동안 많이 늘었긴한데 설득력, 정보 전달의 측면에서는 아직도 먼 듯하다. 뭔가에 쫓기듯이 하지 않고 여유롭게 말하고자 하는 바를 이해시키며 발표하는 능력을 길러보자.

책은 한달에 2권 정도 꾸준히 읽고 있는편이다. 하지만 올해 중반부터 책을 읽기만 하고 남아있는게 없다는 느낌을 받았다. 좀 어려운 책은 무슨 내용이 있었는지 기억도 안나는 것이 있다.

이 문제를 해결하고자 저번부터 책 내용을 정리하고 느낀점을 기록하려고 하고 있다. 그런 과정에서 책에서 어떤 내용이 와닿았는지 포스트잇으로 남기는 중. 이제 어떻게 기록을 남길지는 써보면서 해봐야겠다.

문제는 기록을 남기는 속도가 느리다는 것. 읽고나서 바로바로 기록을 남기면 좋겠지만 생각보다 그게 안된다. 괜찮게 읽은 책만 남기는게 좋을 듯 하다.

올해는 한달에 한 권만 기록을 글로 남기는 것이 목표

사진

사진 블로그도 만들면서 포트폴리오를 만들어보려는 중. 뭔가 사진 프로젝트를 하나 해보려고 마음만 먹는데 진행이 되질 않는다. 치열한 고민을 하고 생각해봐야하는데 그럴 시간이 나지도 않고 다른 것에 치여 우선순위가 밀리는 중이다.

사진 찍고 현상하고 좋은 사진을 남기고만 있다. 이런 방식으로는 사진 취미가 재미없어질것이고 실제로 사진 찍는 날들이 점점 더 줄고 있다. 사진을 좀 더 깊이, 재미있게 즐기기 위해서는 프로젝트를 하며 나의 작품들을 만들어야 한다.

올해는 딱 하나의 프로젝트만 만들어 보는 것이 목표. 생각도 많이해야겠지만, 일단 많이 찍어야한다.

내 인생에서 가장 좋은 일, 가장 안좋은 일이 모두 크게 있던 한 해다. 삶 자체에 대해 많은 생각을 하게 되었다. 삶이란 뭔지, 어떻게 살아야하는지, 무엇이 우선시 되어야 하는지가 올해를 기점으로 많이 바뀌었다.