OAuth2.0과 PKCE

Daren Kim·2024년 3월 28일
0

최근에 우리가 사용하는 서비스들은 대부분 카카오톡이나 구글 등 다양한 채널을 통한 소셜 로그인 기능을 지원한다. 이에 기반이 되는 프로토콜은 이름하야 OAuth 2.0!!

흔히 볼 수 있는 소셜 로그인 화면 예시..

더욱이 많은 신규 서비스들이 사용자 입장에서 보다 접근성 좋고 간편한 로그인 방식을 제공하고자 하고 있는 현 시점에서 이러한 인증 흐름과 방식을 파악하는건 매우 중요하다고 생각하기에 Oauth 2.0이 어떠한 부분을 담당해주는 프로토콜인지, 나아가 여기서 파생될 수 있는 문제를 보안하기 위한 PKCE에 대하여 학습하고 알아보고자 이 글을 쓴다.

OAuth?

일단 2.0에 대하여 살펴보기 이전에 OAuth가 무엇인지 알아보고자 한다.
OAuth의 정의를 먼저 살펴보자면..

OAuth는 Open Authorization의 약자로 인터넷 사용자들이 해당 사이트 혹은 어플리케이션에 비밀번호를 제공하지 않고 다른 웹사이트 상의 자신들의 정보에 대해 웹사이트나 애플리케이션의 접근 권한을 부여할 수 있는 공통적인 수단으로서 사용되는 접근 위임을 위한 개방형 표준(프로토콜)이다.

자칫 대번에 이해하기 어려운 맥락인듯 하지만 쉽게 풀어서 이해해보자면 인터넷에서 다른 서비스나 앱이 사용자의 정보에 접근할 수 있도록 허용하는 방식이다.

예를 들어 우리가 만든 어떠한 서비스가 사용자의 인스타그램 팔로워 목록을 받아와야 한다고 예를 들어보자.
이때 사용자의 팔로워 목록을 받기 위해서 해당 정보에 접근할 수 있도록 사용자로부터 직접 인스타그램 ID와 PW를 받는다면...
간단하고 단순한 방법이지만 보안측면에서는 위험할 수 있다.
만약 이 과정에서 우리 웹사이트에 저장된 사용자의 인스타그램 ID/PW가 해킹으로 탈취된다면..?

이러한 리스크로 인하여 기존의 서비스들은 각자가 구축한 방식으로 인증 과정을 진행하였으나, 각 서비스마다 구축한 방식들의 차이가 있었기 때문에 개별적으로 개발 및 유지보수가 필요했다.
이를 위해 트위터의 주도하에 표준화된 OAuth1.0 버전이 등장하게 되었다.
그 후 모바일 클라이언트 등에서의 더 안정적이고 안전한 사용과 개선을 거쳐 현재는 2.0의 버져닝으로 표준화 되어 사용되고 있다.
기본적인 골자는 다양한 플랫폼의 특정한 사용자 데이터에 접근하기 위해 써드파티(우리의 서비스)가 사용자의 접근 권한을 위임 받을 수 있는 표준 프로토콜이라는 것이다.

OAUth 구성 요소

학습하면서 OAuth를 구성하고 있는 용어들이 꽤나 헷갈리는 부분들이 많았어서 OAuth는 어떤 요소들로 구성되어 있는지, 해당 요소들이 어떤걸 나타내는지 정리하고자 한다.
크게 네가지의 구성요소로 나눌 수 있는데 아래와 같다.

구성 요소설명
리소스 소유자(Resource Owner)일반적으로 사용자를 의미. 자신의 데이터에 대한 접근 권한을 다른 애플리케이션에게 허용할 수 있는 주체. 리소스는 보통 개인정보.
리소스 서버(Resource Server)사용자의 정보를 보유하고 있는 서버. OAuth를 사용하여 접근 권한을 얻은 애플리케이션에게 사용자 데이터에 대한 접근을 제공.(구글, 카카오 등)
클라이언트(Client)사용자의 데이터에 접근하려는 애플리케이션이나 서비스를 의미. 사용자로부터 인증을 받아 리소스 서버에 접근할 수 있는 권한(토큰)을 얻는다. 즉 우리가 보통 개발하는 서비스가 여기에 해당한다.
인증 서버(Authorization Server)사용자의 인증 및 클라이언트에게 접근 토큰을 발급하는 역할을 담당. 이 서버는 클라이언트가 사용자의 데이터에 접근하기 위해 필요한 권한을 관리하고, 인증 과정을 진행. 즉 권한을 부여해주는 서버.

해당 요소들이 서로 주고 받아지는 과정은 아래와 같다.

Authorization code flow

리소스 소유자가 인증을 통해 액세스 토큰을 요청하고 받게 되는데 이 방식이 여러가가 있으며 이를 Authorization grant라고 한다. 현재 시점에서는 Authorization code 방식이 주로 사용되고 있는데 아래와 같은 흐름으로 진행된다.

Athorization Code: 클라이언트와 소유자 사이에 인증서버를 두고 액세스 토큰을 얻는 방식.
가장 기본적으로 사용되며 클라이언트는 인증서버를 통해 웹사이트를 열고 여기서 리소스 소유자 라는걸 인증한다. 이후 code를 받고 이 코드로 액세스 토큰과 교환한다. 인증 흐름에서 클라이언트가 개입하는 부분이 없는것이 특징이다.

  • 사용자 인증 요청: 클라이언트는 사용자를 인증 서버의 로그인 페이지로 리다이렉트. 이때, 클라이언트는 리다이렉션 URL, 요청한 접근 범위(scope), 그리고 상태(state) 같은 정보를 함께 전송.

  • 사용자 로그인 및 권한 부여: 사용자는 인증 서버에서 로그인을 하고, 클라이언트가 자신의 데이터에 접근하는 것을 승인.

  • 인증 서버가 클라이언트에게 인증 코드 발급: 사용자가 로그인하고 권한을 부여하면, 인증 서버는 클라이언트의 리다이렉션 URL로 사용자를 다시 보내면서 인증 코드를 함께 전송.

  • 클라이언트가 인증 코드를 사용해 액세스 토큰 요청: 클라이언트는 받은 인증 코드를 인증 서버에 전송하고, 액세스 토큰을 요청한다. 이때, 클라이언트는 자신을 인증하기 위한 자격 증명(클라이언트 ID와 비밀번호)을 함께 제공.

  • 인증 서버가 액세스 토큰 발급: 인증 서버는 클라이언트의 요청을 검증한 후, 액세스 토큰(그리고 선택적으로 리프레시 토큰)을 발급.

  • 클라이언트가 액세스 토큰을 사용하여 리소스 서버에 접근: 클라이언트는 받은 액세스 토큰을 사용해 리소스 서버에 사용자 데이터에 대한 접근을 요청할 수 있게 된다.

PKCE

이러한 방식에도 역시나 보안적인 취약점은 존재했는데 바로 클라이언트가 액세스 토큰을 요청할때 소위 client secret이라고 불리우는(위 예시에선 클라이언트 ID/PW)를 보내는 부분이다.
Authorization code flow는 클라이언트 secret을 보내는 부분에 의존하고 있고 이는 역시 그러한 정보가 탈취될 수 있는 위험성을 품고 있다.이를 개선하기 위해 PKCE라고 불리우는 Oauth 2.0의 확장된 버전이 등장하게 된다.
(픽시라고 발음한다고 한다. 난 계속 촌스럽게 한글자 한글자 읽어왔다.)

PKCE는 무엇을 해결했나?

Authorization Code flow의 가장 큰 문제점은 위에서 이야기 했듯, 클라이언트 client secret을 안전하게 저장할 수 없다는 부분이다. 이를 위해 PKCE는 기존의 secret을 동적인 문자열로 대체하였다. PKCE 플로우는 노출된 client secret을 제거하면서 OAuth 플로우를 시작한 앱이 액세스 토큰을 요청하는 앱과 동일한지 인증 서버가 확인할 수 있도록 한다.

PKCE에 추가된 부분

PKCE는 크게 세가지를 변경/추가 하여 그 목적을 달성한다.

  • code verifier: 암호화되어 생성된 랜덤 문자열. 최종 액세스 토큰 요청과 authotization 요청의 상관여부 판단에 사용된다.(같은곳에서의 요청인지를 확인)
  • code challenge: 해싱된 문자열(sha 256기반의 base 64 인코딩 값) 서버에서 복호화되며 같은 클라이언트에서 왔는지 판단한다.
  • code challenge method: 해싱된 문자열을 판단하는 함수

PKCE Flow

PKCE는 기존의 AUthorization code flow를 기반으로 개선된 확장 사양이기 때문에 그 흐름은 기존과 크게 다르지 않지만 위에서 이야기한 부분이 추가되어 진행된다.

  1. 클라이언트는 code_verifier를 생성.

  2. 클라이언트는 S256 암호화를 사용하여 code_verifier를 변환하여 code_challenge를 생성.

  3. 클라이언트는 초기 인증 요청과 함께 code_challenge와 code_challenge_method를 서버에 전송.

  4. 서버는 authorization_code로 응답.

  5. 클라이언트는 authorization_code와 code_verifier를 토큰 엔드포인트에 전송.

  6. 서버는 초기 인증 요청에서 받은 code_challenge_method를 사용하여 code_verifier를 변환하고, 그 결과를 code_challenge와 비교. 두 문자열의 값이 일치하면 서버는 요청이 동일한 클라이언트로부터 왔음을 검증하고 access_token을 발급.

마치며..

우리가 사용자의 입장에서 자주 사용하는 동시에 서비스를 만드는 사람으로써, 심도있게 안전에 신경쓰며 개발해야 하는 인증과정에 있어서 어쩌면 직접 ID와 비밀번호를 입력하는 과정은 다소 복잡한 UX가 되버렸는지도 모르겠다.
특히나 웹환경 뿐이 아닌 모바일과의 크로스 플랫폼이 더욱 중요해지는 요즘, 그 과정에서의 인증 흐름과 보안적인 측면에서의 취약점과 개선방향을 알아 볼 수 있던 좋은 기회였다.

출처

PKCE What and Why?
auth0.com
OAuth2.0
OAuth2.0 블로그

profile
안녕하세요!여기저기관심많은FE개발자지망생입니다.

0개의 댓글