OAuth!

OAuth

OAuth(Open Authorization)
위키: 사용자가 자신의 자격 증명을 제공하지 않고 제3자 애플리케이션에 자신이 소유한 자원의 제한적인 접근 권한을 부여할 수 있는 표준 프로토콜

참고
https://datatracker.ietf.org/doc/html/draft-ietf-oauth-v2-1-07
https://opentutorials.org/course/3405
https://www.youtube.com/watch?v=zEysfgIbqlg&list=PLKCk3OyNwIzuD_jxWu-JddooM2yjX5q99&index=4

대표적으로 각종 캘린더, 사진첩 등 Google Drive 를 사용하는 서드파티 앱을 예로 들 수 있다.
서드파티 앱에 Google Drive 계정을 넘기지 않고 Google Drive 에 접근을 허가시킬 수 있음.

OAuth 사용시 얻을 수 있는 장점은 아래와 같다.

  • 보안성
    사용자는 자신의 로그인 정보(자격 증명)를 서드파티 앱에 제공하지 않으므로 보안 강화.
  • 범위 제한
    엑세스 토큰별로 리소스 인가 범위를 명확하게 설정 가능.
  • 토큰 만료
    액세스 토큰의 만료를 설정하고 접근제어 가능.

용어 설명

1

  • Resoucrce
    • 사용할 데이터,
    • ex: Google Drive 내부 사용자 파일
  • Resoucrce Owner
    • 접근하려는 자원의 소유자,
    • ex: Google Drive 계정주인
  • Resource Client
    • 로그인 자원을 이용하는 클라이언트 앱,
    • 웹서버 혹은 모바일 앱
    • ex: Google Drive 를 연계해서 관련 서비스를 만드는 서드파티 앱
    • Resource Client 종류는 아래와 같이 나뉜다.
      • Confidential Client
        client_id, client_secret 을 보관할 수 있는, 서버와 같은 별도의 저장공간이 있는 곳에 위치하는 Resource Client
      • Public Client
        모바일 어플처럼 시크릿 정보를 보관할 수 없는 Resource Client
  • Resoucrce Server
    • 로그인 자원을 관리하는 서버
    • ex: Google Drive 서버
  • Authorization Server
    • 인증 서버
    • ex: Google OAuth 서버

Grant Type

                    1.2. Protocol Flow

    +--------+                               +---------------+
    |        |--(1)- Authorization Request ->|   Resource    |
    |Resource|                               |     Owner     |  Front Channel
    | Client |<-(2)-- Authorization Grant ---|               |
    |        |                               +---------------+
    +--------+

    +--------+                               +---------------+ 
    |        |--(3)-- Authorization Grant -->| Authorization |
    |        |                               |     Server    | 
    |        |<-(4)----- Access Token -------|               |
    |Resource|                               +---------------+
    | Client |                                                  Back Channel
    |        |                               +---------------+
    |        |--(5)----- Access Token ------>|    Resource   |
    |        |                               |     Server    |
    |        |<-(6)--- Protected Resource ---|               |
    +--------+                               +---------------+

                 Figure 1: Abstract Protocol Flow

Front Channel, Back Channel 을 어떻게 사용하는지에 따라 4가지 시나리오가 있으며 Grant Type 이라 부른다.

  1. Authorization Code Grant Type
  2. Client Credential Grant Type
  3. Resource Owner Grant Type
  4. Implict Grant Type

Grant Type 별로 인증방식은 유사하며 Front Channel, Back Channel 섞어 사용한다.

  • (1) ~ (2) 과정은 클라이언트가 직접 수행하는 Front Channel
  • (3) ~ (6) 과정은 리다이렉션을 통해 자동으로 처리되는 Back Channel

그리고 Resource Client 의 종류에 따라서 Grant Type 의 사용 가능 여부가 갈린다.

Authorization Code Grant Type

  • 3 legged flows
  • 리다이렉트를 사용함으로 웹 브라우저 환경에 적합함
  • Back Channel 이 필요하여 Confidential Client 에서만 사용 가능.
  • 대부분의 Confidential Client 기반 Resource Client 가 해당 방식을 사용함

Authorization Code Grant Type 지원 Resource Client 웹페이지에서 사용자가 OAuth를 사용한 페이스북 로그인 버틀을 누르면 아래와 같은 URL 로 로그인 모달창이 열린다.

https://www.facebook.com/dialog/oauth?
app_id=933793539013400&
client_id=933793539013400&
display=popup&
domain=en.airline.example.com&
response_type=token,signed_request&
scope=["email","user_birthday"]&
locale=en_US&
origin=1&
redirect_uri=https://Fstaticxx.facebook.com/connect/xd_my-demo-application/...
sdk=joey

참고
app_id 는 Resource Client 를 나타내는 고유ID, 매칭되는 app_secret 이 있으며 app_secret 은 노출되면 안된다.

로그인 성공시 데이터가 전송될 redirect_uri 이 적혀있다. 적혀진 URI 로 인증정보가 같이 전달되도록 한다.

 +----------+
 | Resource |
 |   Owner  |
 +----------+
       ^
       |
       |
 +-----|----+          Client Identifier      +---------------+
 | .---+---------(1)-- & Redirection URI ---->|               |
 | |   |    |                                 |               |
 | |   '---------(2)-- User authenticates --->|               |
 | | User-  |                                 | Authorization |  Front Channel
 | | Agent  |                                 |     Server    |
 | |        |                                 |               |
 | |    .--------(3)-- Authorization Code ---<|               |
 +-|----|---+                                 +---------------+
   |    |                                         ^      v
   |    |                                         |      |
   ^    v                                         |      |
 +----------+                                     |      |
 |          |>---(4)-- Authorization Code --------'      |
 | Resource |          & Redirection URI                 |       Back Channel
 |  Client  |                                            |
 |          |<---(5)----- Access Token ------------------'
 +----------+       (w/ Optional Refresh Token)
              
              Figure 3: Authorization Code Flow

UserAgentResource Client 에서 제공하는 Web Browser(모달창)이다.

  1. Resource Owner 인증 후 리다이렉트될 링크가 적용되어 있는 로그인 모달창을 Authorization Server 에 등록
  2. Resource Owner 는 해당 모달창에서 로그인 진행
  3. 로그인 성공 시 Authorization Code 를 리다이렉트 URI 에 저장 후 Resource Client 로 리다이렉트
  4. Resource Client 는 전달받은 Redirection URI, Authorization Code, Client ID, Client SecretAccess Token 을 요청
  5. Authorization ServerRedirection URI, Authorization Code, Client ID, Client Secret 검증 후 Access Token 발급
    • Back Channel 과정에서 추가로 Refresh Token 을 전달받을 수 있음.
    • Access Token 이 리다이렉트 URI 로 노출되지 않기에 안전하게 사용자(Resource Owner) 대신 Resource 를 요청할 수 있음.

Authorization Code Grant Type 을 지원하는 Authorization Server 에서 아래 3가지 데이터를 관리한다.

  • Authorization Code
    • 로그인 성공시 이동될 리다이렉트 URI 에 같이 전달되는 랜덤 문자열
    • Resource Owner 을 증명하는 임시발급 인증코드라 할 수 있다.
  • Access Token
    • Authorization Code 를 사용해서 Resource Owner 와 매핑되는 Access Token 을 발급한다.
    • 아래 2가지 종류로 나뉜다.
    • Refrence Token : Authorization Server 에서 관리하는 랜덤 문자열, Resource Server 는 매 요청마다 Access TokenAuthorization Server 에서 확인해야하는 번거로움이 있음.
    • Self Contained Token : JWT 와 같이 서명값이 있어 자기 증명이 가능한 토큰
  • Refresh Token
    • Back Channel 사용 Grant Type 에서 Access Token 과 같이 발급되는 재발급 토큰
    • 구글 Authorization Server Access Token 유효기간은 1시간
    • 구글 Refresh Token 의 경우 별도로 만료되는 시간이 없다고 함
    • 장기간 유효기간을 가지며 로그인이 풀리지 않는 UX 구성시 사용한다

Authorization Code Grant Type - PKCE

모바일 앱과 같이 브라우저 환경이 아닌경우 위와 같이 리다이렉트를 사용하는 Authorization Code 인증방식은 사용하기 힘들 수 있다.
그럴경우 Authorization Code, access token 요청 모두 공개 클라이언트(프론트, 모바일 앱 등)에서 수행해야 한다.

하지만 공개 클라이언트에선 Resource Client 의 인증으로 사용하는 client_secret 을 사용하지 못하기 때문에 다른 방식을 사용하는데, PKCE (Proof Key for Code Exchange) 방식으로 Resource Client 의 인증을 수행한다.

별도 백엔드 서비스를 사용하지 않고 모바일 앱만 사용하는 경우에 PKCE 를 사용한다,
대부분 서비스에 백엔드가 존재하다 보니 client_secret 을 사용하는 첫번째 방식을 사용.

  • (1) Client Identifier & Redirection URI 단계에서 Resource Client(모바일앱) 는 랜던값인 code_verifier 를 생성하고 해시값인 code_challenge 를 redirect URL 에 포함하여 전달
    • code_challenge 는 서명역할을 하며 중간자 공격을 방지한다.
    • Authorization Code 가 유출되어도 code_challenge, code_verifier 보안단계가 하나 더 있다.
    • 추가로 랜덤 난수인 state, nonce 를 생성하여 전달한다.
    • state 는 CSRF 방지를 위한 값으로 사용자가 아래 링크로 로그인 성공시 동일한 state 값이 redirect URL 파라미터로 전달된다.
    • nonceOpenID Connect 에서 JWT 토큰에 삽입되는 값으로 토큰재생공격을 방지한다.
http://authorization-server:9090/oauth2/authorize?
  response_type=code&
  client_id=oauth-demo-client-id&
  scope=openid%20profile%20email&
  redirect_uri=com.myapp:/oauth2redirect& # 모바일 app link
  state=znoqBBJcIPiMhva-Ze527g2sYhyFg3u_g7GpYF3-0WQ%3D&
  nonce=C317bREycoVNZm3kUcswIBh_eVu8jXnL7hu95mQurNo&
  code_challenge=bu_IDU5aUm1igD7jbfca8-8KwOC7Ot342d_hnYcmn0k& # code_verifier 를 해시한 값
  code_challenge_method=S256

위 2개 추가 파라미터를 통해 client_secret 을 사용하지 않아도 정상앱인척 하는 Authorization Server 로의 공격요청을 방지한다.

  • 사용자가 로그인 한 뒤 성공하면 위 redirect URL 과 파라미터가 전송된다. statecode_verifier 를 찾기 위한 매핑값으로 캐시에 저장된다.
com.myapp:/oauth2redirect?
code=abc123XYZ& # auth code
state=znoqBBJcIPiMhva-Ze527g2sYhyFg3u_g7GpYF3-0WQ%3D
  • (4) Authorization Code & Redirection URI 단계에서 Resource Client(모바일앱)access token 요청시 [grant_type, code, redirect_uri, client_id, code_verifier] 을 Form data 에 설정해서 Authorization Server 로 전달한다.
  • Authorization Server 는 가지고 있던 code_challengecode_verifier 가 매칭되는지 확인 후 access token 을 발급한다.

발급된 access token 으로 백엔드 서비스에서 로그인여부를 파악하려면 해당 access token 이 예상한 client id 에서 생성된 것인지 검증 과정을 수행해야 한다.

Client Credential Grant Type

인증정보를 Resource Client(앱) 에게 직접 전달하는 방식이라 거의 사용하지 않음.

  • 2 legged flows
  • Confidential Client 만 사용.
  • Back Channel 만 사용하며 사전에 Resource Owner 인증정보 가 필요함.
  • Resource ClientResource Owner 의 인증정보 사용하여 Authorization Server 에게 직접 Access Token 을 요청함.
  • Authorization Server 와 연동가능한 인증정보를 Confidential Client 가 가지고 있어야 해서 거의 지원하지 않음.
+---------+                                  +---------------+
|         |                                  |               |
|         |>--(1)- Client Authentication --->| Authorization |
| Client  |                                  |     Server    |  Back Channel
|         |<--(2)---- Access Token ---------<|               |
|         |                                  |               |
+---------+                                  +---------------+
            Figure 4: Client Credentials Grant

Resource Owner Credentials Grant Type

인증정보를 Resource Client(앱) 에게 직접 전달하는 방식이라 거의 사용하지 않음.

  • 2 legged flows
  • User Password Authentication Flow 라 부르기도 함.
  • Resource OwnerResource Client 를 믿고 ID/PWD 를 넘겨주는 방식
  • Resource ClientAuthorization Server 에 전달받은 ID/PWD 를 사용해 Access Token 을 요청.
  • Public Client 가 사용하지만 보안상 취약하여 Authorization Server 에서 지원하지 않는 경우가 많음.
  • OAuth 1.0 에서 사용하던 방식
+----------+
| Resource |
|   Owner  |
+----------+
    |
    |
    | Authenticate with client(Username, Password)
    |
    v
+---------+                                  +---------------+
|         |                                  |               |
|         |>--(1)- Client Authentication --->| Authorization |
| Client  |                                  |     Server    | Back Channel
|         |<--(2)---- Access Token ---------<|               |
|         |                                  |               |
+---------+                                  +---------------+

Implicit Grant Type

  • 2 legged flows
  • OAuth 2.1 에서 deprecated 됨
  • Authorization Code 방식과 동일하게 리다이렉트 방식이지만 Authorization Code 대신 Access Token 을 바로 전달받음
  • 리다이렉트 URL 에 Access Token 이 노출되어 보안에 취약함(Refresh Token 은 전달하지 않음)
  • 브라우저 기반 리다이렉트를 지원하는 SPA 형태 Public Client 에서 사용가능
  • Confidential Client 에서도 사용 가능하지만 Authorization Code 방식을 선호함
 +----------+
 | Resource |
 |   Owner  |
 +----------+
       ^
       |
       |
 +-----|----+          Client Identifier      +---------------+
 | .---+---------(1)-- & Redirection URI ---->|               |
 | |   |    |                                 |               |
 | |   '---------(2)-- User authenticates --->|               |
 | | User-  |                                 | Authorization | Front Channel
 | | Agent  |                                 |     Server    |
 | |        |                                 |               |
 | |    .--------(3)-- Redirect URI With  ---<|               |
 +-|----|---+             Access Token        +---------------+
   |    | 
   |    | 
   ^    v 
 +---------+
 |         |
 |  Client |
 |         |
 +---------+

Grant Type 중 유일하게 Resource ClientAuthorization Server 가 직접 통신하는 Back Channel 과정이 없다.

Refresh Token Grant Type

Back Channel 이 있는 Grant Type 에서 추가적으로 지원하는 Grant Type.
Access Token 을 전달받으면서 같이 발급된 Refresh Token 을 사용해 새로운 Access Token 을 발급받을 수 있다.

+--------+                                           +---------------+
|        |--(1)------- Authorization Grant --------->|               |
|        |                                           |               |
|        |<-(2)----------- Access Token -------------|               |
|        |               & Refresh Token             |               |
|        |                                           |               |
|        |                            +----------+   |               |
|        |--(3)---- Access Token ---->|          |   |               |
|        |                            |          |   |               |
|        |<-(4)- Protected Resource --| Resource |   | Authorization |
| Client |                            |  Server  |   |     Server    |
|        |--(5)---- Access Token ---->|          |   |               |
|        |                            |          |   |               |
|        |<-(6)- Invalid Token Error -|          |   |               |
|        |                            +----------+   |               |
|        |                                           |               |
|        |--(7)----------- Refresh Token ----------->|               |
|        |                                           |               |
|        |<-(8)----------- Access Token -------------|               |
+--------+           & Optional Refresh Token        +---------------+
        
            Figure 2: Refreshing an Expired Access Token

OAuth 의 허점

Access Token, Refresh Token 을 통해 사용자 접근 허용을 관리함으로 토큰을 탈취할 수 있는 해킹공격에 취약하다.

Access Token 은 보통 해당 브라우저의 local storage, HTTP Cookie 등에서 관리되기 때문에 악성코드를 대신 실행시키는 CSRF, XSS 의 공격대상이 되기 쉽고,
GET HTTP URL 에 인증코드가 그대로 유출되기 때문에 중간자 공격에 취약하다. HTTPS 를 사용한다 하더라도 DNS 스푸핑과 같은 공격으로 인해 무력화될 수 있다.

  • CSRF
  • 토큰 도용(XSS 등으로 토큰을 도용)
  • 토큰 하이재킹(중간자 공격)

이를 막기 위해 Private Resource Client 는 자신만 아는 secret 을 함께 사용하여 Access Token 을 요청하고
Public Resource Client 또한 code challenge 와 같은 서명기능을 사용해 Access Token 을 요청한다.

OpenID Connect(OIDC)

https://openid.net/specs/openid-connect-core-1_0.html

OpenID Connect(OIDC)OAuth 프로토콜을 기반으로 권한과 더불어 사용자의 신원을 검증하는 인증 기능을 추가지원한다.
OAuth 2.0 프로토콜에 JWT 를 추가한 신원 확인 프로토콜 이다.

OIDC 에선 Access Token 의 형태가 Opaque Token(랜덤 문자열) 타입 대신 JWT 를 사용한다.
그리고 사용자의 추가적인 신원데이터를 포함한 JWT 형태의 ID Token 을 추가하여 반환한다.

OAuth 에서 사용하는 Access Token, Refreth Token 외에 ID Token 이 추가되었다.

ID Token 내부에는 아래와 같이 JWT Claims 형태로 OIDC 가 지원하는 신원데이터 형식, HTTP 헤더의 최대 사이즈인 4KB 이내로 저장가능하다.

{
  "iss": "https://server.example.com",
  "sub": "24400320",
  "aud": "s6BhdRkqt3",
  "nonce": "n-0S6_WzA2Mj",
  "exp": 1311281970,
  "iat": 1311280970,
  "auth_time": 1311280969,
  "acr": "urn:mace:incommon:iap:silver"
}

JWTAuthorization Server 의 비공개키로 서명되어 있어 출처 인증이 가능하다.

OIDC Flow

문서에선 OAuth 와 비슷한 역할을 수행하지만 새로운 이름을 가진 리소스들로 설명한다.

  • Relying Party(RP)
    • Resource Client 의 연장선
    • ID Token 을 사용하는 어플리케이션
  • OpenID Provider(OP)
    • Authorization Server 의 연장선
    • Authorization Code, Access Token, Refresh Token, ID Token 을 발급
  • Identity Provider(IDP)
    • 인증서비스에서 사용하는 일반적인 통칭, IDP 안에 Authorization Server, OP 개념이 포함된다.
+--------+                                   +--------+
|        |                                   |        |
|        |---------(1) AuthN Request-------->|        |
|        |                                   |        |
|        |  +--------+                       |        |
|        |  |        |                       |        |
|        |  |  End-  |<--(2) AuthN & AuthZ-->|        |
|        |  |  User  |                       |        |
|   RP   |  |        |                       |   OP   |
|        |  +--------+                       |        |
|        |                                   |        |
|        |<--------(3) AuthN Response--------|        |
|        |                                   |        |
|        |---------(4) UserInfo Request----->|        |
|        |                                   |        |
|        |<--------(5) UserInfo Response-----|        |
|        |                                   |        |
+--------+                                   +--------+

OAuth 2.0Authroization ServerOP 의 차이점은 Grant Type 과정에서 Access Token 을 반환하는 과정에 OpenID 에 필요한 데이터를 같이 삽입하여 반환하거나,
그림 (4) ~ (5) 과정에서 Access Token 을 사용해 UserInfo 를 요청할 수 있는 기능을 추가로 제공한다.

UserInfoID Token보다 훨씬 상세한 데이터를 가지고 있다.
UserInfo 를 제공하는 서버는 RP 가 아닌 Resource Server 로 따로 구축하는 경우도 있다.

OIDC 에서는 Access Token, ID Token 을 발급하기 위한 3가지 Flow 를 사용한다.

대부분 Authorization Code Flow 를 사용한다.

  • Authorization Code Flow
    • Back Channel 에서 수행하는 Access Token, Refresh Token 발급과정에 ID Token 을 같이 껴서 반환하게 된다.
    • Back ChannelFlow 에 개입하기에 Confidential Client 에서만 사용 가능하다.
  • Implict Flow
    • 리다이렉트 URI 에 Access Token, ID Token 을 포함시켜 반환한다.
  • Hybrid Flow
    • Authorization Code, Implict 2가지 Flow 를 섞어 사용하는 방식
    • Back ChannelFlow 에 개입하기에 Confidential Client 에서만 사용 가능하다
    • 보안적으로 노출되어도 상관 없는 Authorization Code, ID Token 은 리다이렉트 URI 에 포함시켜 반환
    • 노출되면 위험한 Access TokenBack Channel 에서 Authorization Code 를 사용해 요청한다.
    • Access Token 을 요청하면서 ID Token 을 다시한번 수신받는데, 이전에 받은 ID Token 과 교차 검증한다.

OAuth Device Flow

https://auth0.com/docs/get-started/authentication-and-authorization-flow/device-authorization-flow

1

IoT, Smart TV 와 같이 입력환경이 제한된 상태에서 기기에 대한 인증을 수행하고 싶을 때 사용하는 flow

1

  1. 사용자가 Netflix TV App 을 킴
  2. Netflix TV App 에서 인증을 위해 Authorization Server 에 요청
  3. Authorization Server 에서 device_code, user_code, verficiation_url 반환
    • device_code
      device_client 가 인증 서버에게서 받는 장치식별코드.
      인증 수행, 토큰 저장소의 index 용도로 사용.
    • user_code
      device_client 가 인증 서버에게서 받는 사용자 식별 코드(보통 8자리).
      device_client 의 승인을 위해 사용된다.
    • verification_uri
      사용자 검증 URI, 사용자가 에이전트(브라우저 등)에 입력하여 연결.(보통 QR코드로 접속)
      URI는 짧고 기억하기 쉬워야 하며, 사용자가 쉽게 입력할 수 있어야 합니다.
  4. 사용자는 user_code 를 확인하고 해당 verification_url 에 접속
    • 사용자 로그인 (Browser Flow) 수행
  5. Netflix TV App 은 사용자가 휴대폰으로 로그인할 때 까지 interval pooling 을 수행
  6. 사용자가 user_code 를 입력하여 device 승인 했는지 determine(확인)
  7. device 승인이 되었다면 interval pooling 응답으로 Access Token 발급
  8. Access Token 으로 Resource Server 에 API 요청

3번 과정에서 아래와 같은 json 값을 반환받는다.

{
  "device_code": "4/0AY0e-g7YZ4xQ...",
  "user_code": "G3Q4",
  "verification_uri": "https://example.com/device",
  "verification_uri_complete": "https://example.com/device?user_code=G3Q4",
  "expires_in": 1800,
  "interval": 5
}
// 1800초동안 5초마다 pooling

verification_uri_complete “user_code” 를 포함하는 검증 URI 입니다. URI 에 user_code 를 포함하고 있으므로 사용자가 직접 user_code 를 입력하지 않고 인증 과정을 진행할 수 있습니다. 주로 QR, NFC 와 같은 non-textual verification 방식에서 사용되며 애플리케이션의 사용성 향상을 위해 활용됩니다. expires_in 필수 “device_code”와 “user_code”의 수명을 초 단위로 나타내며, 이 시간이 지나면 코드는 만료됩니다. interval 선택 Device Client 가 토큰 엔드포인트에 폴링 요청을 보내는 사이에 기다려야 하는 최소 시간(초)을 나타냅니다. 값이 제공되지 않을 경우, Device Client 는 기본적으로 5초 간격으로 폴링해야 합니다.

카테고리:

업데이트: