getting_started_with_oauth_2.0 책을 읽으면서 정리한 내용입니다. 책 이외의 내용이 포함되어 있습니다.
OAuth는 Open Authorization으로 애플리케이션 인증을 위한 접근 관한 개방형 프로토콜이다. 근래 서비스를 보면 OAuth를 표준 인증/인가 프로토콜을 사용하고 있다(자체 로그인은 지원하지 않는 경우도 빈번하다)
개발을 공부하다보면, OAuth를 통한 인증 인가를 피하기 어려운데, 단순해보이는 것과 달리 OAuth를 제대로 이해하기 못하면 OAuth 로직 구현에 많은 시간을 할애한다.
사이드 프로젝트중 OAuth를 다시 한번 만나게 되었는데, 이번 기회를 통해 OAuth를 정리하고자 한다.
OAuth의 발전 과정을 알아보면서 OAuth를 이해해보자
OAuth 1.0
우리가 알고 있는 OAuth는 2.0이다. OAuth는 트위처가 개발한 OAuth 1.0를 시작으로 개발되었다.
OAuth 1.0이전에는 각 Provider가 자체적으로 개발한 권한 부여 API를 통해 인증/인가 처리를 할 수 있었다.(구글의 AuthSub, 야후의 BBAuth) OAuth 1.0를 통해 웹에서 수백개의 API를 통한 단일 인가처리를 허용하였다.
Flow는 다음과 같다.
0. 인증/인가 엔드포인트에 접근
1. 클라이언트가 인증서버에게 인가를 요청 (리소스 사용자의 리소스를 인가해줘)
2. 인증서버에서 인증을 요구 (인가전에 인증을 먼저 해줘)
3. 인증 페이지 전환(302 redirect)
4. 리소스 사용자 인증 및 인증 값 반환
5. 요청 코드 클라이언트에게 전달
6. 인증 서버에게 인증값 전달
7. 엑세스 토큰 반환
OAuth 1.0에서의 보안
OAuth 1.0에서는 어떤 보안 조치를 했을까? 먼저 OAuth 1.0은 http 환경을 가정한다. 따라서 요청 데이터가 암호화 되지 않는다.
OAuth 1.0에서는 요청마다 서명값을 포함시켜 통신한다. 다음은 OAuth 1.0에서 사용한 요청 값 예시이다.
POST /initiate HTTP/1.1
Host: photos.example.net
Authorization:
oauth realm="Photos",
oauth_consumer_key="dpf43f3p2l4k3l03",
oauth_signature_method="HMAC-SHA1",
oauth_timestamp="137131200",
oauth_nonce="wIjqoS",
oauth_callback="http%3A%2F%2Fprinter.example.com%2Fready",
oauth_signature="74KNZJeDHnMBp0EMJ9ZHt%2FXKycU%3D"
oauth_signature_method를 통해 암호화 방식을 결정한뒤 oauth_signature에 서명값을 통해 요청이 변조되지 않았음을 보장한다.
추가적으로 OAuth 1.0에서는 요청 토큰에 취약점이 발견되었다.
- 요청 토큰을 저장후 피해자의 인증과정에서 해당 요청 토큰을 사용하도록 유도
- 피해자는 해당 토큰을 통해 엑세스 토큰 발급
- 공격자는 요청 토큰을 통해 피해자의 리소스에 접근가능한 엑세스 토큰을 획득
OAuth Core 1.0a
[RFC2616] Fielding, R., Gettys, J., Mogul, J., Frystyk, H., Masinter, L., Leach, P., and T. Berners-Lee, “Hypertext Transfer Protocol -- HTTP/1.1,” RFC 2616. [RFC2617] Franks, J., Hallam-Baker, P., Hostetler, J., Lawrence, S., Leach, P., Luotonen, A.,
oauth.net
OAuth 1.0(2007)의 취약점을 보안한 OAuth 1.0a(2009)가 발표되었다.
OAuth 2.0
2012에 발표된 OAuth 2.0은 기존 OAuth 1.0의 단점 일부를 고친 형태로 발표되었다. 가장 큰 변화는
- https 기반 인증 + Bearer 토큰
- 요청 코드에서 인가 코드로 전환
- 스코프를 통한 엑세스 범위 설정
- 리프레시 토큰
- 다양한 Grant Type
이 있다.(일부)
Bearer Token 과 TLS
OAuth 2.0에서는 토큰을 소지한 클라이언트만 자원에 접근을 허락하고, 기존의 서명을 제외한 형태로 토큰을 사용한다.
서명 대신 TLS(HTTPS)를 통해 전송중인 데이터에 대한 보안을 보장한다 (TLS를 모른다면 클라이언트와 서버간에 인증서를 통해 하나의 키를 생성하여 HTTP 메세지를 암호화하여, 클라이언트와 서버를 제외한 공격자로부터 HTTP 메세지를 보호한다고 이해하자)
Grant Type
하나의 인증 흐름만 존재하던 OAuth 1.0와 달리 OAuth 2.0 에서는 상황에 맞게 사용할 수 있는 다양한 인증 흐름을 제공한다.
Authorization code
- 서버 사이드 에서 리소스 소유자가 데이터에 대한 엑세스를 허용한 뒤, URL에 있는 권한 코드와 같이 클라이언트(서버)로 redirect
- 클라이언트 내부적으로 권한 코드를 통해 엑세스 토큰을 획득
- 엑세스 토큰을 위해 자격증명을 필요로
Implicit grant for browser-based client-side applications
- 리소스 소유자가 애플리케이션에 대해 엑세스를 허용한뒤 엑세스 토큰을 즉시 발행
- 권한 코드, 리프레쉬 토큰 지원 X
Resource owner password-based grant
- 리소스 소유자가 사용자 이름과 비밀번호를 OAuth 엑세스 토큰으로 교환
Client credentials
- 클라이언트 자체를 자격 증명, 사용자의 리소스에 접근 하지 못하고, 용도가 다름
Device profile
- 웹 브라우저가 내장되어 있지 않거나, 입력옵션이 제한되는 환경에서 OAuth를 사용할 수 있도록 제공
- 별도의 컴퓨터에서 웹사이트에 접속하여 인증 코드를 입력하여 장치에 대한 엑세스 승인
가장 대중적인 인증 흐름인 Authorization code flow를 확인해보자
OAuth 2.0 Flow
0. 엔드포인트 접근
1. 권한 부여 서버(인가 서버) 에게 권한 부여 요청
2. 인증 요청 (redirect 및 주소 반환)
3. 리소스 사용자 인증 및 권한 허가
4. 인증 코드 클라이언트에게 전달
5. 권한 부여 서버에게 엑세스 토큰 요청 (+ 리프레쉬 토큰)
6. 엑세스 토큰 반환
7. 리소스 서버에게 사용자 정보 요청
8. 엑세스 토큰 확인 후 반환
OAuth 2.0 에서 보안
OAuth 2.0에서 발생할 수 있는 보안 이슈를 생각해보자
스니핑 위험이 있는가?
-> HTTPS으로 방어
인가 토큰이 탈취 당할 여지가 있는가?
-> 먼저 인가 토큰을 Redirect를 통한 OAuth 로그인중 url에 인가 토큰을 명세하는 경우, 탈취 위험성 발생
엑세스 토큰 또는 리프레쉬 토큰이 탈취 당하면?
-> 대처하기 어렵다
OAuth 2.1
OAuth 2.0은 OAuth 1.0에서 발생할 수 있는 보안문제를 해결하였지만 일부를 해결하지 못하였다. OAuth 2.1에서는 2.0보다 더 강화된 보안을 제공한다. (Authorization code 대부분의 Grant Type이 Deprecated 된다)
다양한 보안 옵션중 PKCE와 리프레시 토큰 회전만 다루겠다.
리프레시 토큰 회전은 리프레시 사용시 재발급되도록 권한 부여 서버에서 처리 되는 것으로 리프레시 토큰을 갱신할때, 리프레시 토큰을 악용하더라도 이미 리프레시 토큰을 만료시키기 위한 보안 정책이다.
PKCE
Proof Key for Code Exchange으로 클라이언트가 권한 부여 서버에게 인증 토큰 요청시 클라이언트에서 임의로 정한 첼린지값의 해시값을 같이 보내고, 엑세스 토큰 요청시에도 동일한 해시값을 통해 외부로의 엑세스 토큰 요청으로 부터 방어하는 정책이다.
1, 5에서 owner에서 알 수 없는, 클라이언트(서버)만 알 수 있는 해시값을 같이 보낸다.
OAuth 2.1에서 보안
OAuth 2.1에서 해결한 OAuth 2.0의 보안 이슈를 확인해보자
스니핑 위험이 있는가?
-> HTTPS으로 방어
인가 토큰이 탈취 당할 여지가 있는가?
-> 먼저 인가 토큰을 Redirect를 통한 OAuth 로그인중 url에 인가 토큰을 명세하는 경우, 탈취 위험성 발생
-> 인가 토큰이 탈취 되더라도 해시값(Code Challenge)을 방어
엑세스 토큰 또는 리프레쉬 토큰이 탈취 당하면?
-> 리프레시 토큰 회전(사용시 재발급)