oauth2.0_thumbnail

OAuth 2.0 프로토콜은 외부 서비스의 권한 위임에 위해 사용되는 프로토콜입니다.

OAuth 2.0 RFC 공식 문서

OAuth2.0은 왜 필요했을까?

일반 사용자들이 앱을 통해서 Google이나 제 3자 서비스들에 저장된 자기 정보에 접근하기 위해서 가장 간단한 방법은 제 3자 서비스의 비밀번호를 앱에 공유하는 것입니다.

하지만, 이러면 “앱”은 사용자들의 제 3자 서비스 계정의 비밀번호를 알게 되고 관리해야하며, 이는 보안상 중요한 정보입니다.

이를 해결하기 위해서 OAuth2.0이 등장했습니다.

OAuth 1.0과의 차이점

동일한 문제를 해결하기 위한 프로토콜로서 OAuth 1.0이 있었습니다.

공식문서에 의하면 OAuth2.0은 기존의 비밀번호 공유 모델의 한계를 해결하고, 안전하고 세분화된 위임(access delegation)을 표준화하기 위해 만들어졌습니다.

OAuth 1.0

OAuth 1.0은 “서명 기반(Signature)” 위임 프로토콜입니다.

역할: Consumer(클라이언트), Service Provider(자원/권한 서버 역할 겸함), Resource Owner(사용자).

토큰 체계: request token(임시) → access token(영구) 각각에 secret(비밀키) 가 쌍으로 있음. 매 요청을 토큰/컨슈머 시크릿으로 서명해서 보냄.

서명·보호: HMAC-SHA1, RSA-SHA1, PLAINTEXT 등 서명 방식 + nonce/timestamp로 재사용(재전송) 공격 방지. 요청 요소들을 합친 Signature Base String을 만들어 서명.

  1. Request Token 획득 클라이언트가 서명한 요청으로 request_token 받음(콜백 URL 포함). 1.0a에선 응답에 oauth_callback_confirmed=true. 
  2. 사용자 승인 & Verifier 발급 사용자를 서비스 제공자의 승인 페이지로 리디렉트 → 승인 후 클라이언트 콜백으로 oauth_token + oauth_verifier 전달. (1.0a에서 추가된 검증 코드로 세션 고정 취약점 대응) 
  3. Access Token 교환 클라이언트가 요청 토큰 + oauth_verifier 로 서명 요청 → access_token + access_token_secret 수령.  
  4. 보호 자원 접근 이후 API 호출마다 access token/secret로 서명해 요청. 베어러 토큰이 아니라 매 요청 서명 검증이 핵심.

취약점

1.0의 경우 oauth_token + oauth_verifier 등의 정보를 Query parameter에 함께 전달하는데 이렇게 되면 브라우저 history에 남게 되어 탈취의 위험이 있었습니다.

또한, 일부 TLS 미사용 구현이 있어 탈취의 위험이 있었습니다.

이런 1.0의 세션 고정(session fixation) 문제를 막기 위해 1.0a에서 oauth_verifier 가 도입되었습니다.

OAuth 2.0의 과정

제 앱에서 Google 로그인 기능으로 로그인하는 상황을 가정해보겠습니다.

Google 로그인은 정확히는 OIDC(OpenID Connect) 프로토콜이고 OIDC 표준은 OAuth2.0 표준을 기반으로 하고 있습니다.

참여자

여기에서 주요 참여자는 총 4명입니다.

  • Client : 나의 앱
  • Resource Owner : 사용자
  • Resource Server: Google
  • (Authorization Server): Google (권한 서버)

OAuth 2.0 준비

Client가 Resource Owner(사용자)에게 권한을 요청하기 위해서는 먼저 OAuth2.0 프로토콜을 준비해야 합니다.

  1. Authorization Server에게 Client ID와 Client Secret을 발급받습니다.
  2. 요청 권한 Scope를 정의합니다.
  3. Redirect URI를 설정합니다.

AccessToken 발급 과정

  1. 사용자가 구글 로그인을 시도
  2. (로그인 되어 있지 않다면) 사용자가 구글 로그인
  3. 사용자가 승인을 마치면 Authorization Server 가 Redirect URI 로 authorization code 를 쿼리에 담아 사용자 에이전트(브라우저) 를 리디렉트
  4. 클라이언트(서버 백엔드)는 Authorization Server에 authorization code, client_id(+ client_secret, 해당 시), PKCE code_verifier(공개 클라이언트) 를 제출해 Access Token(± Refresh Token)을 발급
  5. 클라이언트는 발급받은 Access Token 으로 Resource Server(Google API)에 사용자 정보를 요청
  6. Client는 AccessToken을 사용하여 Resource Server에 접근하여 사용자 정보를 조회
  7. Client는 AccessToken이 만료되면 RefreshToken을 사용하여 AccessToken을 재발급

Bearer Token?

RFC 6750 - OAuth 2.0 Bearer Token Usage

Authorization 헤더에 보면 자주 Bearer <token> 형식으로 사용됩니다. 왜 굳이 Token 앞에 Bearer를 붙일까요?

RFC 6750 공식문서와 함께 알아보겠습니다.

RFC 6750이 왜 필요했을까?

해당 규약은 TLS 사용을 전제로 만들어진 토큰 전달과 사용 방법에 대한 구체적인 규약입니다.

  • HTTP 규약 준수 HTTP 표준에는 Authorization: <scheme> <credentials> 형식이 필요했는데, OAuth 토큰에 맞는 새로운 스킴을 만들어야 했습니다. OAuth 2.0에서 보안을 위해 Authorization 헤더를 사용하라고 정한 만큼 HTTP Authorization 헤더 규약을 맞출 필요가 있었습니다.
  • 토큰을 어떻게 싣고 전달해야하는가?에 대한 구체적인 정의 Access Token을 준다고는 되어있지만, 전달 후에 어떻게 사용해야하는지 정의되어 있지 않은데 이를 보강합니다.

Bearer 토큰이란?

Bearer 토큰은 “이 토큰을 소지한 어떤 주체(bearer)든, 다른 어떤 주체가 이 토큰을 가지고 사용할 수 있는 모든 방식으로 똑같이 사용할 수 있는” 성질을 가진 보안 토큰입니다.

즉, Bearer 토큰을 사용하는 데에는 암호학적 키 자료(Proof-of-Possession) 의 소유를 증명할 필요가 없습니다.

단순히 토큰을 가지고 있다는 사실만으로 접근 권한이 부여되는 소지자 기반 토큰입니다.

보안 리스크

소지자 기반 토큰인 만큼 탈취되면 그걸 가진 누구나 쓸 수 있어 주의가 필요합니다.

Reference

생활코딩 OAuth2.0 유튜브 OAuth2.0 RFC 공식 문서 OAuth1.0 RFC 공식 문서 RFC 6750 - OAuth 2.0 Bearer Token Usage