OAuth2 소셜로그인 처리(1), OAuth2 소셜로그인 처리(2)를 작성했을 당시 주위에서 구현이나 개념에 대해 여쭤보셨던 분들이 많았습니다.
하지만 이번에 OAuth2기반 인증 구현을 Spring Security없이 구현을 해보면서 이전에 부족한 개념으로 진행을 했었다는 걸 깨닫고 이번 기회에 자세하게 다루어보고자 합니다.
이 글은 OAuth2.0 공식문서만을 기반으로 작성한 내용입니다.
OAuth2.0은 서드 파티(third-party) 앱이 HTTP Service에 대한 제한된 액세스 권한을 갖게 해주는 인가 프레임워크입니다. 서드 파티 앱이 직접 Resource에 접근하거나, HTTP Service-Resource Owner간 승인받은 통신을 할 수 있도록 합니다.
기존에 OAuth가 없던 시절에는 서드 파티가 resource에 접근하려면 Resource Owner의 credentials를 서드 파티가 공유해야만 인증이 가능했습니다.
이때 credentials는 ID/PW값 등의 기밀정보를 의미합니다.
이 방식은 당연히 안전하지 않습니다.
1. 서드 파티 앱이 credentials를 별도로 저장해두어야 합니다.
2. 패스워드 기반의 인증을 서버가 제공해야 합니다.(보안 이슈)
3. 여러 서드 파티가 하나의 패스워드 값만으로 resource에 대한 권한을 무한히 가집니다.
이 문제를 해결하고자 OAuth는 Authorization Server를 별도로 두기로 하였습니다.
Authorization Server는 Resource Owner가 승인한 Access Token을 발급합니다. 이 토큰은 생명주기, 권한 범위 등의 설정이 되어 있습니다. 이 토큰을 가지고 Client는 resource에 접근할 수 있습니다.
OAuth1.0은 작은 ad-hoc 환경을 위해 만들어졌던 초기 프로토콜입니다. (RFC 5849) 이 글에서는 깊게 다루지 않겠지만 간단히 설명하자면 아래의 차이가 있습니다.
1. 토큰 재발급이 용이해짐
2. 특정 부분에 대한 권한만 제어할 수 있음
3. 각 서드 파티마다 액세스 토큰 발급이 가능해짐
4. 웹 어플리케이션을 벗어난 다양한 환경에서 사용 가능
OAuth2.0은 4가지 역할을 가지고 있습니다.
자원에 대한 접근권한을 제어하는 주체입니다. 사용자(end-user)일수도 있고, 기관일 수도 있습니다.
Google OAuth를 이용한다면, Google계정을 가진 사용자입니다.
자원이 존재하는 서버입니다. Access Token을 보고 자원을 제공할지 결정합니다.
Google Calendar 정보를 가진 Google이 Resource Server입니다.
resource를 요청하는 주체입니다. 사용자라기 보다는 OAuth를 위임시킨 주체로, Resource Owner를 대신하여 요청을 보내는 어플리케이션입니다.
Spring Server를 구축하여 Google에게 Calendar 정보 요청을 한다면, Spring Server가 Client입니다.
Access Token을 발급해주는 주체입니다. Resource Server와 같을 수도 있지만 표준 스펙이라고 할 수는 없습니다.
Google이 로그인 완료 시 Access Token도 같이 발급해주기 때문에 Google입니다.
OAuth2.0의 인가 과정입니다.
여기서 Authorization Grant를 진행하는 방식이 여러개로 나뉘어집니다.
Client가 Resource Server에 직접 권한을 요청하는 방식이 아닌, Authorization Server에 먼저 요청하여 authorization code를 받는 방식입니다.
이 방식은 resource owner의 credentials를 client가 절대로 알 수 없기에 가장 많은 oauth provider가 채택하고 있습니다.
Authorization Server의 중간다리 없이 Client가 직접적으로 Resource Server에게서 access token을 받는 방식입니다.
이 방식은 access token과 더불어 resource server의 user-agent까지 노출되기 때문에 보안 이슈가 있습니다. 따라서 권장되지 않는 방법입니다.
user-agent는 resource owner가 사용하는 소프트웨어를 의미합니다.
resource owner의 ID/PW와 같은 credentials를 client가 이미 가지고 있는 방식입니다. Access Token 발급을 위해 해당 credentials을 요청에 담아 전송합니다.
이 방식 역시 당연하게도 권장되지 않는 방법입니다.
이전에 이미 인가 권한을 받았고, 제한적인 resource에 대한 권한만 필요로 할 때 사용하는 방식입니다. Client credentials을 이용하여 authorization grant가 됩니다.
JWT를 이용하여 Spring Security 필터를 통과시키던 방식이 바로 여기에 해당합니다.
인가 허가가 되었으면 access token이 발급됩니다. 이 토큰은 허가가 필요한 resource에 접근하는데 필요합니다.
Refresh Token
refresh token은 생명주기가 짧은 access token을 재발급하기 위해 존재하는 별도의 토큰입니다. 이때 재발급되는 access token은 지금보다 더 적은 권한을 가질 수도 있습니다.
Refresh Token을 사용하는 것은 OAuth2.0이 요구하는 필수 스펙은 아닙니다.
프로토콜을 적용하기 전, Client는 Authorization Server에 등록하는 절차(Redirection URI, client type 등)가 필요합니다. 어떤 방식으로 등록할지는 따로 표준이 정해져있지 않지만, 등록자체는 필수적입니다.
Authorization Server는 임의로 client type을 지정하여 OAuth 기능을 제공하면 안됩니다. 각 client type별로 적절한 secure 인증방식을 제공하여 이용할 수 있도록 해야합니다.
Client가 직접 credentials의 기밀을 유지할 능력을 가졌거나, 안전한 client authentication을 진행할 수 있는 능력을 가진 타입
별도의 보안 서버를 구축해두었고, credentials에 대한 접근 제한을 둘 수 있는 경우를 의미합니다.
Client가 직접 credentials의 기밀을 유지할 능력을 가지지 못한 타입
네이티브 앱이나 웹 브라우저 위에서 동작하는 앱이 여기에 속합니다.
Client ID는 각 client마다 가지는 고유값입니다. 이 값 자체는 외부에 노출되어도 상관없지만, client 인증을 진행할 때 단독으로 사용하면 안됩니다.(PW등 필요)
프로토콜이 flow대로 흘러가면서 거치는 endpoint는 여러가지가 존재합니다.
Authorization Server - Resource Owner
이 endpoint는 Authorization Server가 Resource Owner를 식별하고, authorization grant를 제공하는 부분입니다.
ID/PW나 Session Cookie를 application/x-www-form-urlencoded방식으로 전송하여 credentials를 받습니다. 이때 HTTP Response로 받기 때문에 외부 노출을 방지하기 위해 Authorization Server가 Request시 TLS 전송이 필요합니다.
Response에는 반드시 response_type
파라미터가 존재해야 합니다.
Authorization Server - Client
이 endpoint는 Authorization Endpoint이후 Resource Owner의 user-agent를 Client에게 돌려주는 부분입니다.
URI endpoint는 여러개 지정할 수 있습니다. 이는 Authorization Server의 재량에 달려있습니다. 만약 여러 redirection url이 가능하다면, Client가 request시 redirect_uri
파라미터에 URI값을 명시해주어야 합니다.
Redirect URI에 있는 모든 HTML 응답이 처리되기 때문에 Client는 서드 파티 스크립트 등을 응답 처리에 담아서는 안됩니다. Client는 credentials 정보만 뽑아내고, 해당 user-agent 정보를 가지고 다른 endpoint로 리디렉션해야 합니다. 따라서 credentials는 redirection 수행 시에 외부로 노출되면 안됩니다.
Client - Authorization Server
이 endpoint는 authorization grant를 기반으로 access token을 얻는데 사용됩니다. 따라서 별도의 인가 과정없이 access token을 얻는 implicit 방식은 이 endpoint가 존재하지 않습니다.
Scope는 허용할 권한의 범위를 나타냅니다. 여기서는 자세히 다루지 않도록 하겠습니다.
https://datatracker.ietf.org/doc/html/rfc6749#section-3.3
OAuth2.0 공식문서 4~7챕터에서는 각 endpoint 요청 및 응답 시 필수/선택적으로 넣어야할 parameter를 설명하고 있습니다.
해당 부분은 그때마다 참고하는 것이 유용하다고 생각하기 때문에 링크만 남기도록 하겠습니다.
OAuth2.0 공식문서 9챕터에서는 native app에 대한 설명을 하는데, OAuth2.0 for Native Apps 공식문서가 나온 만큼 해당 문서와 같이 참고하시면 좋습니다.
OAuth2.0 공식문서 10챕터에서는 각종 보안 이슈에 대한 주의사항을 설명하고 있습니다.