RFC 6749
RFC 6749는 OAuth 2.0 권한 부여 프레임워크(The OAuth 2.0 Authorization Framework)를 정의하는 인터넷 표준 문서이다. 이 문서는 2012년 10월에 인터넷 표준화 기구인 IETF(Internet Engineering Task Force)에 의해 발행되었다. 주 저자는 Dick Hardt이며, 여러 기술 전문가들의 협업으로 만들어졌다.
OAuth 2.0은 이전 버전인 OAuth 1.0(RFC 5849)의 후속 버전으로, 다양한 웹 애플리케이션, 데스크톱 애플리케이션, 모바일 애플리케이션 및 IoT 장치에서 안전한 권한 위임을 가능하게 하는 프로토콜이다. 간단히 말해, OAuth 2.0은 사용자가 자신의 비밀번호를 공유하지 않고도 제3자 애플리케이션에 자신의 데이터에 대한 제한된 접근 권한을 부여할 수 있도록 해주는 프레임워크이다.
OAuth 1.0에서 OAuth 2.0으로의 전환은 단순한 버전 업그레이드가 아닌 완전한 재설계였다. OAuth 2.0은 OAuth 1.0보다 구현이 더 간단하고, 모바일 애플리케이션과 같은 다양한 클라이언트 유형을 더 잘 지원하며, 더 나은 확장성을 제공한다. 그러나 이런 단순화는 보안 모델의 변화도 수반했다.
OAuth 2.0의 기본 개념과 용어
OAuth 2.0을 이해하기 위해서는 먼저 다음과 같은 핵심 용어와 개념을 이해해야 한다:
주요 역할(Roles)
OAuth 2.0 프레임워크에는 네 가지 주요 역할이 있다:
- 리소스 소유자(Resource Owner): 보호된 리소스에 접근 권한을 부여할 수 있는 엔티티로, 일반적으로 최종 사용자이다. 예를 들어, 자신의 Google 계정 데이터에 접근 권한을 부여하는 사용자이다.
- 리소스 서버(Resource Server): 보호된 리소스를 호스팅하는 서버로, 액세스 토큰을 사용하여 보호된 리소스 요청을 수락하고 응답할 수 있다. 예를 들어, Google의 API 서버가 이에 해당한다.
- 클라이언트(Client): 리소스 소유자의 권한으로 보호된 리소스에 접근을 요청하는 애플리케이션이다. 예를 들어, 사용자의 Google 계정에 접근하려는 제3자 애플리케이션이 이에 해당한다.
- 권한 부여 서버(Authorization Server): 리소스 소유자를 인증하고 권한을 얻은 후 클라이언트에게 액세스 토큰을 발급하는 서버이다. 예를 들어, Google의 OAuth 서버가 이에 해당한다.
토큰(Tokens)
OAuth 2.0은 두 가지 주요 토큰 유형을 사용한다:
- 액세스 토큰(Access Token): 보호된 리소스에 접근하기 위한 자격 증명으로, 일반적으로 문자열 형태이다. 이 토큰은 리소스 소유자가 클라이언트에게 부여한 권한 범위, 기간 등의 정보를 나타낸다.
- 리프레시 토큰(Refresh Token): 액세스 토큰이 만료된 후 새 액세스 토큰을 얻기 위해 사용되는 자격 증명이다. 액세스 토큰보다 일반적으로 수명이 길고, 경우에 따라 발급되지 않을 수도 있다.
클라이언트 유형
OAuth 2.0은 다양한 클라이언트 유형을 지원한다:
- 기밀 클라이언트(Confidential Client): 클라이언트 자격 증명(비밀)을 안전하게 보관할 수 있는 클라이언트로, 일반적으로 웹 서버에서 실행되는 애플리케이션이다.
- 공개 클라이언트(Public Client): 클라이언트 자격 증명을 안전하게 보관할 수 없는 클라이언트로, 일반적으로 브라우저에서 실행되는 JavaScript 애플리케이션이나 모바일 앱이 이에 해당한다.
권한 부여 유형(Grant Types)
RFC 6749는 다양한 사용 사례를 지원하기 위해 네 가지 기본 권한 부여 유형을 정의한다:
- 권한 부여 코드(Authorization Code): 클라이언트가 권한 부여 서버로부터 권한 부여 코드를 얻은 다음, 이 코드를 액세스 토큰으로 교환하는 방식이다. 이는 서버 사이드 웹 애플리케이션에 가장 적합하다.
- 암시적 부여(Implicit): 간소화된 권한 부여 코드 흐름으로, 권한 부여 코드 없이 액세스 토큰을 직접 발급받는다. 주로 브라우저 내 JavaScript 애플리케이션에 사용된다.
- 리소스 소유자 비밀번호 자격 증명(Resource Owner Password Credentials): 리소스 소유자의 자격 증명(아이디/비밀번호)을 클라이언트가 직접 사용하여 액세스 토큰을 얻는 방식이다. 높은 수준의 신뢰가 필요하며, 다른 방식이 불가능할 때만 사용해야 한다.
- 클라이언트 자격 증명(Client Credentials): 클라이언트가 자신의 자격 증명만을 사용하여 액세스 토큰을 얻는 방식으로, 클라이언트가 리소스 소유자를 대신하지 않고 자체적으로 리소스에 접근할 때 사용한다.
OAuth 2.0 권한 부여 흐름 상세 분석
권한 부여 코드 부여(Authorization Code Grant)
이 흐름은 웹 애플리케이션과 같은 기밀 클라이언트에 가장 적합하며, 다음과 같은 단계로 진행된다.
권한 요청: 클라이언트는 사용자를 권한 부여 서버로 리다이렉트하여 권한을 요청한다.
사용자 인증 및 권한 부여: 권한 부여 서버는 사용자를 인증하고 클라이언트 요청에 대한 허가를 요청한다.
권한 부여 코드 발급: 사용자가 권한을 부여하면, 권한 부여 서버는 클라이언트로 권한 부여 코드와 함께 사용자를 리다이렉트한다.
액세스 토큰 요청: 클라이언트는 권한 부여 코드를 사용하여 액세스 토큰을 요청한다.
액세스 토큰 발급: 권한 부여 서버는 클라이언트의 신원을 확인하고 권한 부여 코드를 검증한 후, 액세스 토큰과 선택적으로 리프레시 토큰을 발급한다.
이 흐름의 주요 장점은 높은 보안성과 리프레시 토큰 지원이다. 클라이언트 비밀이 사용자에게 노출되지 않고, 액세스 토큰도 프론트 채널(브라우저)을 통해 전달되지 않는다.
암시적 부여(Implicit Grant)
이 흐름은 브라우저 기반 애플리케이션(SPA)과 같은 공개 클라이언트에 적합하며, 다음과 같은 단계로 진행된다:
권한 요청: 클라이언트는 사용자를 권한 부여 서버로 리다이렉트한다. 이때
response_type=token
으로 설정한다.사용자 인증 및 권한 부여: 권한 부여 서버는 사용자를 인증하고 권한을 요청한다.
토큰 발급: 사용자가 권한을 부여하면, 권한 부여 서버는 액세스 토큰을 URI 프래그먼트에 포함시켜 클라이언트로 사용자를 리다이렉트한다.
토큰 사용: 클라이언트는 URI 프래그먼트에서 액세스 토큰을 추출하여 보호된 리소스에 접근하는 데 사용한다.
이 흐름은 권한 부여 코드 흐름보다 단순하지만, 보안 측면에서 몇 가지 단점이 있다. 액세스 토큰이 브라우저를 통해 전달되므로 노출 위험이 있으며, 리프레시 토큰을 지원하지 않는다.
리소스 소유자 비밀번호 자격 증명 부여(Resource Owner Password Credentials Grant)
이 흐름은 클라이언트가 리소스 소유자의 자격 증명을 직접 수집하여 액세스 토큰을 얻는 방식이다:
자격 증명 수집: 클라이언트는 리소스 소유자로부터 직접 사용자 이름과 비밀번호를 획득한다.
토큰 요청: 클라이언트는 이 자격 증명을 사용하여 권한 부여 서버에 액세스 토큰을 요청한다.
토큰 발급: 권한 부여 서버는 자격 증명을 검증하고 액세스 토큰을 발급한다.
이 방식은 리소스 소유자와 클라이언트 간에 높은 신뢰가 있을 때만 사용해야 한다. 예를 들어, 운영 체제 내장 클라이언트나 높은 권한을 가진 애플리케이션에 적합하다.
클라이언트 자격 증명 부여(Client Credentials Grant)
이 흐름은 클라이언트가 자신의 자격 증명만을 사용하여 액세스 토큰을 얻는 방식이다:
토큰 요청: 클라이언트는 자신의 자격 증명을 사용하여 권한 부여 서버에 액세스 토큰을 요청한다.
토큰 발급: 권한 부여 서버는 클라이언트 자격 증명을 검증하고 액세스 토큰을 발급한다.
이 흐름은 리소스 소유자의 컨텍스트가 없는 클라이언트-서버 간 통신에 적합하다. 예를 들어, 백그라운드 서비스나 마이크로서비스 간 통신에 사용된다.
토큰과 범위(Scopes)
액세스 토큰(Access Token)
액세스 토큰은 보호된 리소스에 접근하기 위한 자격 증명으로, 다음과 같은 특성을 가진다:
형식: RFC 6749는 토큰 형식을 명시하지 않으며, 구현에 따라 다양한 형식(불투명 문자열, JWT 등)이 사용된다.
전달 방식: 주로 HTTP Authorization 헤더를 통해 전달되며, 형식은 일반적으로 “Bearer” 토큰 유형을 사용한(RFC 6750).
수명: 액세스 토큰은 일반적으로 짧은 수명(몇 분에서 몇 시간)을 가지며, 이는 토큰 노출 시 위험을 줄이기 위함이다.
리프레시 토큰(Refresh Token)
리프레시 토큰은 새로운 액세스 토큰을 얻기 위해 사용되며, 다음과 같은 특성을 가진다:
용도: 액세스 토큰이 만료된 후 사용자를 다시 인증하지 않고도 새 액세스 토큰을 발급받을 수 있다.
보안: 리프레시 토큰은 액세스 토큰보다 더 민감하므로, 클라이언트는 이를 안전하게 저장해야 한다.
갱신 프로세스: 클라이언트는 리프레시 토큰을 사용하여 다음과 같이 새 액세스 토큰을 요청한다.
갱신 토큰 순환(Rotation): 보안 강화를 위해 새 액세스 토큰을 발급할 때 새 리프레시 토큰도 함께 발급하는 방식으로, 이전 리프레시 토큰은 무효화된다.
범위(Scopes)
범위는 액세스 토큰이 부여하는 권한의 범위를 제한하는 메커니즘이다:
정의: 범위는 일반적으로 공백으로 구분된 문자열 목록으로 표현된다. 예:
scope=read_profile edit_profile read_contacts
요청: 클라이언트는 권한 요청 시 필요한 범위를 지정할 수 있다.
동의 화면: 권한 부여 서버는 요청된 범위에 기반하여 사용자에게 동의 화면을 제시한다.
토큰 응답: 발급된 토큰의 범위는 응답에 포함될 수 있으며, 요청된 범위보다 좁을 수 있다.
범위 확인: 리소스 서버는 액세스 토큰과 관련된 범위를 확인하여 요청된 리소스에 접근할 권한이 있는지 판단한다.
OAuth 2.0의 보안 고려사항
RFC 6749는 OAuth 2.0 구현 시 고려해야 할 다양한 보안 측면을 다루고 있다.
클라이언트 인증
클라이언트 인증은 권한 부여 서버가 토큰을 요청하는 클라이언트의 신원을 확인하는 과정이다:
클라이언트 비밀(Client Secret): 기밀 클라이언트는 권한 부여 서버에 등록 시 받은 비밀을 사용하여 인증한다.
인증 방법:
- HTTP Basic 인증
1
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
- 요청 본문 파라미터
1
client_id=s6BhdRkqt3&client_secret=gX1fBat3bV
공개 클라이언트: 공개 클라이언트는 클라이언트 비밀을 안전하게 보관할 수 없으므로, 대안적인 인증 메커니즘(예: PKCE)이 권장된다.
권한 코드와 액세스 토큰 보호
권한 코드와 액세스 토큰을 보호하기 위한 고려사항:
- 수명 제한: 권한 코드는 매우 짧은 수명(일반적으로 몇 분)을 가져야 하며, 한 번만 사용 가능해야 한다.
- 토큰 기밀성: 액세스 토큰은 권한이 없는 당사자에게 노출되지 않도록 해야 한다.
- TLS 사용: 모든 토큰 교환은 TLS(Transport Layer Security)를 통해 이루어져야 한다.
- 리다이렉션 URI 검증: 권한 부여 서버는 클라이언트로부터 받은 리다이렉션 URI가 등록된 URI와 정확히 일치하는지 확인해야 한다.
일반적인 보안 위협과 대응
OAuth 2.0 구현에서 고려해야 할 주요 보안 위협:
CSRF(Cross-Site Request Forgery):
- 위협: 공격자가 사용자를 속여 의도하지 않은 권한 부여 요청을 수행하게 할 수 있다.
- 대응: 클라이언트는 권한 요청 시
state
파라미터를 사용하여 CSRF 공격을 방지해야 한다.
1
GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
리다이렉션 URI 조작:
- 위협: 공격자가 권한 코드나 액세스 토큰을 자신의 서버로 리다이렉트할 수 있다.
- 대응: 권한 부여 서버는 리다이렉션 URI를 엄격하게 검증해야 한다.
토큰 탈취:
- 위협: 액세스 토큰이 노출되면 공격자가 보호된 리소스에 접근할 수 있다.
- 대응: 짧은 토큰 수명, TLS 사용, 토큰 저장 시 보안 조치 적용 등
클라이언트 가장(Impersonation):
- 위협: 공격자가 합법적인 클라이언트인 것처럼 가장할 수 있다.
- 대응: 안전한 클라이언트 등록 및 인증 절차 구현
PKCE(Proof Key for Code Exchange)
PKCE는 RFC 7636에서 정의된 확장으로, 공개 클라이언트를 위한 보안 강화 메커니즘이다:
목적: 권한 코드 가로채기 공격으로부터 보호한다.
작동 방식:
- 클라이언트는 랜덤 문자열(code_verifier)을 생성한다.
- 이 문자열의 해시(code_challenge)를 계산한다.
- 권한 요청 시 code_challenge와 code_challenge_method(S256 또는 plain)를 포함한다.
- 토큰 교환 시 원래의 code_verifier를 제공한다.
- 권한 부여 서버는 code_verifier의 해시가 이전에 받은 code_challenge와 일치하는지 확인한다.
구현 예:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
# 권한 요청 GET /authorize? response_type=code& client_id=s6BhdRkqt3& state=xyz& redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb& code_challenge=E9Melhoa2OwvFrEMTJguCHaoeK1t8URWbuGJSstw-cM& code_challenge_method=S256 # 토큰 요청 POST /token HTTP/1.1 Host: server.example.com Content-Type: application/x-www-form-urlencoded grant_type=authorization_code& code=SplxlOBeZQQYbYS6WxSbIA& redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb& client_id=s6BhdRkqt3& code_verifier=dBjftJeZ4CVP-mB92K27uhbUJU1p1r_wW1gFWFOEjXk
OAuth 2.0 확장과 후속 발전
RFC 6749 발표 이후, OAuth 2.0 생태계는 다양한 확장과 개선을 통해 발전해왔다.
주요 확장 표준
Bearer Token Usage (RFC 6750):
- 액세스 토큰을 HTTP 요청에 포함시키는 방법을 정의한다.
- Authorization 헤더, 폼 인코딩 바디 파라미터, URI 쿼리 파라미터 등 방법을 명시한다.
Token Revocation (RFC 7009):
- 클라이언트가 더 이상 필요하지 않거나 손상된 것으로 의심되는 토큰을 취소하는 방법을 정의한다.
Dynamic Client Registration (RFC 7591):
- 클라이언트가 권한 부여 서버에 자동으로 등록하고 필요한 정보를 얻는 방법을 정의한다.
JWT for OAuth 2.0 Client Authentication (RFC 7523):
- JSON Web Token(JWT)을 사용하여 OAuth 2.0 클라이언트를 인증하는 방법을 정의한다.
- 클라이언트 비밀 대신 JWT를 사용하여 클라이언트 인증을 가능하게 한다.
Token Introspection (RFC 7662):
- 리소스 서버가 권한 부여 서버에 토큰의 상태와 메타데이터를 질의할 수 있는 방법을 정의한다.
JWT 프로필 및 액세스 토큰 유형(RFC 9068):
- JWT를 OAuth 2.0 액세스 토큰으로 사용하기 위한 표준 프로필을 정의한다.
- 액세스 토큰에 포함되어야 하는 클레임과 검증 규칙을 명시한다.
OAuth 2.1
OAuth 2.1은 현재 개발 중인 규격으로, OAuth 2.0의 개선 버전이다.
주요 변경 사항은 다음과 같다:
- 간소화: 덜 사용되거나 보안 이슈가 있는 권한 부여 흐름 제거(암시적 부여 등)
- PKCE 필수화: 모든 권한 코드 부여 흐름에서 PKCE 사용을 필수로 함
- 리다이렉션 URI 요구사항 강화: 더 엄격한 리다이렉션 URI 검증
- 모범 사례 통합: 여러 확장과 모범 사례를 핵심 사양에 통합
- 보안 권장사항 업데이트: 최신 위협 모델과 대응 방법 포함
OpenID Connect
OpenID Connect(OIDC)는 OAuth 2.0 위에 구축된 인증 레이어로, 다음과 같은 특징이 있다:
- ID 토큰: 사용자 인증 정보를 포함하는 JWT 형식의 토큰
- UserInfo 엔드포인트: 사용자 프로필 정보를 검색하기 위한 표준 API
- 표준화된 범위: email, profile, address 등의 표준화된 정보 범위
- 디스커버리: 서비스 구성 정보를 자동으로 발견할 수 있는 메커니즘
- 세션 관리: 로그아웃 및 세션 상태 확인을 위한 표준 방법
OpenID Connect는 OAuth 2.0의 권한 부여(Authorization) 기능과 함께 인증(Authentication) 기능을 제공하여, 통합 인증 및 접근 제어 솔루션을 구현할 수 있게 한다.
OAuth 2.0 구현 예제
다양한 프로그래밍 언어와 프레임워크에서 OAuth 2.0을 구현하는 방법을 살펴보면:
Node.js 구현 예제
Express.js와 Passport.js를 사용한 OAuth 2.0 클라이언트 구현:
|
|
Spring Boot 구현 예제
Spring Security OAuth2를 사용한 리소스 서버 구현:
|
|
Python 구현 예제
Flask와 Authlib을 사용한 OAuth 2.0 클라이언트 구현:
|
|
OAuth 2.0의 모범 사례
OAuth 2.0을 효과적이고 안전하게 구현하기 위한 모범 사례.
일반적인 모범 사례
- 항상 TLS 사용: 모든 OAuth 2.0 통신은 TLS(HTTPS)를 통해 이루어져야 한다.
- 적절한 권한 부여 흐름 선택:
- 웹 서버 애플리케이션: 권한 부여 코드 부여
- 단일 페이지 애플리케이션(SPA): 권한 부여 코드 부여 + PKCE
- 모바일/데스크톱 앱: 권한 부여 코드 부여 + PKCE
- 서버 간 통신: 클라이언트 자격 증명 부여
- 토큰 수명 관리:
- 액세스 토큰: 짧은 수명(15분-1시간)
- 리프레시 토큰: 더 긴 수명, 필요 시 취소 가능
- 상태 파라미터 사용: 모든 권한 요청에 state 파라미터를 포함하여 CSRF 공격을 방지한다.
- 리다이렉션 URI 검증: 정확한 매칭을 통해 리다이렉션 URI를 검증한다.
클라이언트 측 모범 사례
- 안전한 토큰 저장:
- 웹 애플리케이션: HttpOnly, Secure, SameSite 쿠키
- SPA: 메모리 저장(JavaScript 변수) 또는 안전한 쿠키
- 모바일 앱: 안전한 저장소(iOS Keychain, Android Keystore)
- PKCE 사용: 모든 공개 클라이언트는 PKCE를 사용해야 한다.
- 토큰 갱신 전략: 액세스 토큰 만료 전에 갱신하는 전략을 구현한다.
- 오류 처리: 토큰 만료, 취소 등의 오류 상황을 적절히 처리한다.
서버 측 모범 사례
- 클라이언트 검증: 클라이언트 등록 시 철저한 검증과 승인 절차를 수행한다.
- 범위 제한: 필요한 최소한의 범위만 허용한다.
- 토큰 서명 및 검증: JWT를 사용할 경우 강력한 서명 알고리즘(RS256 등)을 사용한다.
- 무차별 대입 공격 방지: 속도 제한, 계정 잠금 등의 방어 메커니즘을 구현한다.
- 토큰 취소 지원: 토큰 취소 엔드포인트와 취소 목록 관리를 구현한다.
OAuth 2.0의 한계와 도전 과제
OAuth 2.0의 주요 한계와 도전 과제를 살펴보면:
- 프레임워크의 복잡성
- 다양한 흐름: 여러 권한 부여 흐름이 존재하여 적절한 흐름을 선택하고 구현하는 데 복잡성이 증가한다.
- 확장의 파편화: 많은 확장과 프로필이 존재하여 상호 운용성 문제가 발생할 수 있다.
- 구현 차이: 다양한 OAuth 2.0 제공자 간의 구현 차이로 인해 통합이 어려울 수 있다.
- 보안 고려 사항
- 묵시적 흐름 문제: 원래 SPA용으로 설계된 묵시적 흐름은 여러 보안 취약점이 있어 현재는 사용이 권장되지 않는다.
- 피싱 취약성: 사용자가 가짜 권한 부여 화면을 구별하기 어려울 수 있다.
- 토큰 보안: 액세스 토큰이 노출될 경우 보호된 리소스에 무단 접근이 가능하다.
- 오픈 리다이렉터 문제: 부적절한 리다이렉션 URI 검증으로 인해 공격 가능성이 있다.
- 사용자 경험 문제
- 리다이렉션 기반: 리다이렉션 기반 흐름은 일부 환경(embedded 시스템, CLI 도구 등)에서 사용자 경험이 좋지 않을 수 있다.
- 동의 피로(Consent Fatigue): 사용자가 너무 많은 동의 화면에 노출되면 내용을 제대로 읽지 않고 승인하는 경향이 있다.
- 인증서버 종속성: 인증 서버가 다운되면 모든 클라이언트가 영향을 받는다.
용어 정리
용어 | 설명 |
---|---|