OAuth 정리

SooSoo·2021년 9월 20일
1

공부정리

목록 보기
2/7

OAuth란

OAuth2.0은 권한 부여를 위한 산업 표준 프로토콜이다.

OAuth는 인증(Authentication)과 권한(Authorization)을 획득하는 것으로 볼 수 있다.

  • 인증은 자신이 누구라고 주장하는 사람을 확인하는 절차이다
  • 권한부여는 가고싶은 곳으로 가도록 혹은 원하는 정보를 얻도록 허용하는 과정이다.

OAuth의 배경

API 접근 위임에 대한 표준안을 만들기 위해 OAuth가 시작되었습니다.

사용자 입장에서는 써드파티의 서비스를 이용할 때 소셜플랫폼 아이디(이후 네이버로 가정)로 회원가입을 진행한다면 편할 것입니다. 그런데 써드파티에서 제공하는 로그인 폼에 네이버 아이디, 비밀번호를 입력해야 한다면 사용자는 신뢰할 수 없는 서비스에 보안정보를 입력하는 것이므로 꺼림칙할 것입니다. 이때 써드파티에서 안전하게 로그인을 진행하고 사용자 정보를 가져오도록 하는 표준을 제공하는 것이 OAuth의 목적입니다.

따라서 OAuth는 단순 로그인을 목적으로 하는 Authentication과 함께 Authorization을 진행하는 것을 목적으로 합니다. OAuth에서도 인증의 과정을 거치지만 이는 API 사용 인가에 대한 진행 과정으로 생각해야합니다.

이에 대한 비유를 NAVER D2에서 가져왔습니다.

사원증을 이용해 출입할 수 있는 회사를 생각해 보자. 그런데 외부 손님이 그 회사에 방문할 일이 있다. 회사 사원이 건물에 출입하는 것이 로그인이라면 OAuth는 방문증을 수령한 후 회사에 출입하는 것에 비유할 수 있다.

다음과 같은 절차를 생각해 보자.

나방문씨(외부 손님)가 안내 데스크에서 업무적인 목적으로 김목적씨(회사 사원)를 만나러 왔다고 말한다.

안내 데스크에서는 김목적씨에게 나방문씨가 방문했다고 연락한다.

김목적씨가 안내 데스크로 찾아와 나방문씨의 신원을 확인해 준다.

김목적씨는 업무 목적과 인적 사항을 안내 데스크에서 기록한다.

안내 데스크에서 나방문 씨에게 방문증을 발급해 준다.

김목적씨와 나방문씨는 정해진 장소로 이동해 업무를 진행한다.

위 과정은 방문증 발급과 사용에 빗대어 OAuth 발급 과정과 권한을 이해할 수 있도록 한 것이다. 방문증이란 사전에 정해진 곳만 다닐 수 있도록 하는 것이니, '방문증'을 가진 사람이 출입할 수 있는 곳과 '사원증'을 가진 사람이 출입할 수 있는 곳은 다르다. 역시 직접 서비스에 로그인한 사용자와 OAuth를 이용해 권한을 인증받은 사용자는 할 수 있는 일이 다르다.

NAVER D2

위의 과정을 실제 OAuth Flow와 비교하여 살펴보겠습니다.

사전에 알아두어야 할 용어는 다음과 같습니다.

OAuth Roles

  • Authorization server - 액세스토큰을 발급해 줄 서버입니다.
  • Resource Owner - 어플리케이션의 사용자입니다. 액세스 토큰으로 접근하는 것의 Permission을 주는 주체로 표현됩니다. ( 카카오로그인 시에 사용자가 로그인 허용 요청 카톡에 Permission을 주어 인증과정을 완료합니다. 이처럼 Resource Owner는 사용자 본인입니다.)
  • Client - 액세스토큰을 발급받아 Resource Server에 API를 요청하는 애플리케이션입니다. (Resource Owner와 클라이언트가 구분되어 있습니다. Resource Owner가 사용자 본인을 의마한다면 Client는 그 역할을 수행하는 어플리케이션 혹은 브라우저를 의미합니다.)
  • Resource Server - API Server 입니다. Client가 토큰을 통해 요청할 자원을 가지고 있는 서버입니다.

소셜로그인을 제공하는 플랫폼의 경우 Authorization server와 Resource Server를 분리하여 관리한다고 합니다.

OAuth Term

  • grant - 유저(Resource Owner)가 Client에게 인가한것을 의미합니다. grant의 예시로 Authorization Code가 있습니다.
  • Access Token - Authorization Server에서 grant를 받을 경우 발급해주는 토큰입니다.
  • Refresh Token - AccessToken의 경우 만료기간을 짧게 가지고 있습니다. Refresh Token은 옵셔널한 토큰으로 AccessToken이 만료될 경우 새로운 AccessToken을 발급해주는 역할을 수행합니다.

위의 단어들로 표현한 OAuth의 가장 기본적인 흐름은 다음과 같습니다.

  1. Client에서 resource owner에게 authorization을 요청합니다.
  2. owner가 인가를 줄 경우, client는 해당 인가(grant)를 authorization server(소셜플랫폼 인증서버)에 전달합니다.
  3. grant가 valid할 경우에, authorization server는 액세스 토큰을 client에 전달합니다.
  4. Client는 전달받은 access token을 사용하여 resource server와의 API 통신에 사용합니다.

위의 방식을 구체적으로 구현한 OAuth 인증의 종류는 총 4가지입니다.

  • Authorization Code Grant
  • Implicit Grant
  • Resource Owner Password Credentials Grant
  • Client Credential Grant

가장 쉽게 구현되는 Implicit Grant를 살펴보고 문제점을 알아본 뒤,

가장 많이 사용되고 Implicit Grant의 취약점을 보완한 Authorization Code Grant에 대해 살펴보겠습니다.

Implicit Grant


rfc6749

rfc 스펙에 포함된 Implicit Grant Flow 다이어그램입니다.

Resource Owner가 Client를 통해 서비스를 이용하기 때문에, 두 주체를 User Agent로 표현한다고 보았습니다.

A - 클라이언트에서는 User Agent를 Authorization Endpoint로 보내며 플로우를 시작합니다. 클라이언트는 Client ID, Request Scope, Local State, Redirect URI(Authorization Server가 grant 혹은 deny 시에 User agent를 돌려보낼 URI)를 함께 보냅니다.

  • response_type=token : Authorization Server에서 응답하는 방식에 대한 명시입니다. 추후 설명한 Authorization Code flow에서는 type이 code로 명시됩니다.
https://authorization-server.com/auth
 ?response_type=token
 &client_id=29352910282374239857
 &redirect_uri=https%3A%2F%2Fexample-app.com%2Fcallback
 &scope=create+delete
 &state=xcoiv98y3md22vwsuye3kch

B - Authorization server는 Client의 request에 대해 grant 혹은 deny 여부를 결정합니다. B는 두가지 플로우로 분절되어있습니다. Authorization Server에서 '로그인하시겠습니까?' 라는 카톡을 Resource Owner에게 보내면 Owner가 Accept 여부를 결정하여 Authenticate가 진행된다고 생각하시면 됩니다.

C - resource owner가 grant했다고 가정하면, Authorization server는 전달받은 Redirect URI를 통해 User Agent를 redirect 시킵니다. 이때 Redirection URI의 Fragment는 access token이 포함됩니다.

  • Fragment를 사용했던 이유는 페이지의 새로고침없이 브라우저가 URL을 변경할 수 있었기 때문입니다. 이제 History API (React에서 routing할 때의 방식)를 통해 브라우저는 URL을 update할 수 있기 때문에 fragment를 활용한 implicit 플로우의 장점은 없어졌습니다.
  • state는 기존에 request에 포함된 state와 같은 값을 가질 것을 기대합니다. 이를 통해 CSRF에 대한 위협으로부터 protect 합니다.
  • Access Token은 일반적으로 5분에서 10분 사이의 짧은 life-time을 가집니다. 그 이유는 Access Token이 URL을 통해 반환되기때문에 risky하기 때문입니다.
https://example-app.com/redirect
  #access_token=g0ZGZmNj4mOWIjNTk2Pw1Tk4ZTYyZGI3
  &token_type=Bearer
  &expires_in=600
  &state=xcoVv98y2kd44vuqwye3kcq

D, E → 이 과정을 통해 User Agent는 Redirection URI에서 Access Token을 획득하고 지정된 URI로 이동합니다.

G → 클라이언트는 Access Token을 얻어 Resource Server와 통신할 준비를 마쳤습니다.

Implicit Grant Type이 사용되는 경우

Implicit Grant Type은 주로 사용의 편의성 때문에 사용됩니다. 특히 프론트 단에서 Authorization Code Grant Type보다 사용이 용이하기 때문에 채택됐습니다. 그러나 이러한 편의성으로 희생되는 security를 보완하는 과정에서 편의성이 저해되는 경우가 많았고, 애초의 장점을 잃는 경우가 많다고 합니다.

Security가 약해지는 가장 큰 이유는 Access Token이 URL을 통해 직접 전달되기 때문입니다. Access Token이 browser history에 남기 때문에 server는 token의 life-time을 짧게 설정해줘야합니다. 또한 Back Channel을 거치지 않기 때문에 RefeshToken을 받지 않습니다.* (Secure함이 보장되지 않기 때문에 Token을 갱신할 수 있는 RefeshToken 또한 주지 않는 것 같습니다.) 따라서 Client는 주기적으로 AccessToken을 얻는 귀찮은 과정을 거쳐야합니다.

이제 Implicit Grant를 사용할 유일한 이유는 Authorization Server가 CORS를 지원하지 않을 경우입니다. 추후 설명할 Authorization Code grant 방식에서 어플리케이션은 server에 HTTP POST 요청을 날려야합니다. Authorization server가 적절한 CORS 방식을 지원하지 않을 경우에는 Authorization Code grant 방식을 사용할 수 없기 때문에, Implicit flow로 접근합니다.

Implicit Flow에 대한 레퍼런스

What is the OAuth 2.0 Implicit Grant Type?

Back Channel이란

What Is a Back Channel?

Simply, a back channel is an outbound connection to a server on the Internet, automatically established by client software running a PC behind your firewall. It can also be as innocuous as some small bit of information ("cookies") left on a client desktop in an easily accessible location. The purposes of back channel connections and information gathering cookies are numerous, and can be classified as Useful, Questionable, and Evil.

→ 브라우저에서 서버와의 Connection으로 이해했습니다.

What does the term "Backchannel Request" means and how to make backchannel requests

Authorization Code Grant Type


rfc 스펙에 명시된 Authorization Code Grant 다이어그램

rfc6749

위에 명시된 Implicit flow와 비슷합니다. C부터 과정에 변화가 있습니다.

A - 클라이언트에서는 User Agent를 Authorization Endpoint로 보내며 플로우를 시작합니다. 클라이언트는 Client ID, Request Scope, Local State, Redirect URI(Authorization Server가 grant 혹은 deny 시에 User agent를 돌려보낼 URI)를 함께 보냅니다.

  • response_type=code : Authorization Server에서 응답하는 방식에 대한 명시입니다.
https://authorization-server.com/auth
 ?response_type=code
 &client_id=29352915982374239857
 &redirect_uri=https%3A%2F%2Fexample-app.com%2Fcallback
 &scope=create+delete
 &state=xcoiv98y2kd22vusuye3kch

B - Authorization server는 Client의 request에 대해 grant 혹은 deny 여부를 결정합니다. B는 두가지 플로우로 분절되어있습니다. Authorization Server에서 '로그인하시겠습니까?' 라는 카톡을 Resource Owner에게 보내면 Owner가 Accept 여부를 결정하여 Authenticate가 진행된다고 생각하시면 됩니다.

C - resource owner가 grant했다고 가정하면, Authorization server는 전달받은 Redirect URI를 통해 User Agent를 redirect 시킵니다. 이때 Redirection URI의 Fragment는 authorization code가 포함됩니다.

  • state는 기존에 request에 포함된 state와 같은 값을 가질 것을 기대합니다. 이를 통해 CSRF에 대한 위협으로부터 protect 합니다.
  • code의 life time은 1-10분 사이입니다.
https://example-app.com/redirect
 ?code=g0ZGZmNjVmOWIjNTk2NTk4ZTYyZGI3
 &state=xcoiv98y2kd22vusuye3kch

D - Client는 얻은 authorization 코드를 넣은 request를 authorization server의 token endpoint로 보내 access token을 요청합니다. 이 요청에는 code를 얻는데 사용됐던 redirect URL이 포함됩니다.

필요한 Param

  • grant_type=authorization_code
  • code
  • redirect_uri : Optional하기도 합니다. code를 request할 때와 같은지 검증하여 double check해주는 역할.
  • client_id
  • client_secret : token에 대한 요청이 application으로부터 왔음을 인증합니다. 소셜플랫폼에 사용한 앱 ID나 웹 Domain을 등록하면 사전에 제공됩니다.

E - Authorization server는 code와 URL을 검증하여 client를 authenticate 합니다. 유효하다면 server는 access token과 Optional하게 refresh token을 respond 해줍니다.

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-store
Pragma: no-cache

{
  "access_token":"MTQ0NjJkZmQ5OTM2NDE1ZTZjNGZmZjI3",
  "token_type":"bearer",
  "expires_in":3600,
  "refresh_token":"IwOGYzYTlmM2YxOTQ5MGE3YmNmMDFkNTVk",
  "scope":"create delete"
}

Authorization Code Flow가 사용되는 경우

Implicit Flow에 비하여 additional layer of security를 제공하기 때문에 모바일 앱과 웹에서 주로 사용하는 방식입니다.

AccessToken은 브라우저와 서버의 통신을 통한 안전한 back channel에서 이루어지기 때문에 Attacker가 토큰을 intercept 하는 것으로부터 보호받을 수 있습니다.

실제 Authorization Flow 적용 사례

Bearer Authentication란?

API에 접속하기 위해서는 access token을 API 서버에 제출해서 인증을 해야 합니다. 이 때 사용하는 인증 방법이 Bearer Authentication 입니다. 이 방법은 OAuth를 위해서 고안된 방법이고, RFC 6750에 표준명세서가 있습니다.

사용법

예를들어 api 서버가 server.example.com이고, 접근해야 하는 path가 resource이고, access token이 mF_9.B5f-4.1JqM라면 아래와 같이 헤더 값을 만들어서 전송하면 됩니다.

GET /resource HTTP/1.1 Host: server.example.com Authorization: Bearer mF_9.B5f-4.1JqM

Bearer Authentication 에 대해서 살펴봅니다.

사용한 레퍼런스

→ 최대한 공식문서와 공신력있는 도큐먼트를 레퍼런스로 하여 정리했습니다.

Authentication and Authorization

Authentication and Authorization

rfc6749

What is the OAuth 2.0 Authorization Code Grant Type?

OAuth 2.0 and OpenID Connect Overview

OAuth 2.0 암시적 허용 흐름 - Microsoft ID 플랫폼

Microsoft ID 플랫폼 및 OAuth 2.0 인증 코드 흐름 - Microsoft identity platform

NAVER D2

OAuth 란 무엇일까

OAuth 2.0 - Authorization code Grant

profile
꾸준히

0개의 댓글