스프링 프레임워크의 OAuth 인증을 무력화하는 오픈 리다이렉터 – CVE-2019-3778

| 2021-11-30

안녕하세요, 넷마블 보안실 게임보안팀 전희창입니다.

넷마블 보안실에서는 정기적인 보안 취약점 연구를 하고 있습니다. 앞으로 넷마블 기술 블로그를 통해 관련 연구 결과를 공유하고자 합니다. 

이번 글은 스프링 프레임워크에서 OAuth 인증을 무력화하는 오픈 리다이렉터(Open Redirector) 취약점에 대한 내용입니다.

CVE-2019-3778

CVE-2019-3778

최초공개: 2019년 1월 3일

CVE-2019-3778 취약점은 2019년 1월 3일에 최초 공개됐습니다. 어느덧 최초 공개한지 3년이 다 돼 가는군요. 하지만 여전히 OAuth 인증을 사용하는 다양한 서비스에서 지속해서 발견되고 있어서, 연구 과제로 선정했습니다.

CVE-2019-3778 취약점

먼저 이 취약점은 스프링 특정 버전(2.0, 2.1, 2.2, 2.3) 대역에서 발생하며, 스프링 공식 블로그에도 관련 업데이트 노트가 올라와 있습니다. 스프링에서 OAuth 인증 과정에서 엔드포인트 인증으로 ‘Authorization code grant type’을 쓰고 있는 경우, 공격자가 ‘redirect_uri’에 있는 리디렉션 URI를 조작할 수 있다는 내용입니다. 리디렉션 URI를 조작한 후에는 인증 서버가 발급한 리소스 소유자의 인증 코드를 공격자 제어 하에 있는 URI로 리디렉션할 수 있으므로, 공격자에게 내부 시스템이 노출되는 결과로 이어질 수 있습니다.

OAuth(Open Authorization) 인증

OAuth 인증

제3의 앱이 자원의 소유자인 서비스 이용자를 대신해 서비스를 요청할 수 있도록 자원 접근 권한을 위임하는 방법

OAuth는 서드파티 애플리케이션이 HTTP 서비스에 제한적으로 접근할 수 있도록 조율하는 표준 인증 프레임워크입니다. 1.0 버전에서는 프로토콜이라고 정의했었고, 2.0 버전으로 올라오면서 프레임워크라고 정의하고 있습니다. 

우리가 쇼핑몰이나 앱 서비스에 로그인할 때 주로 사용하는 SSO(Single Sign-on)을 구성하는 여러 방법 중 하나로 OAuth가 있기도 합니다. 다른 회사 서비스에 로그인할 때도 쓰지만, 한 회사에서 여러 시스템을 운영 중인 경우에도 각 시스템마다 계정을 통합 관리하며 사용하기 위해 OAuth를 활용합니다. (OAuth에 대한 자세한 내용이나 구현 가이드 등은 OAuth 2.0 공식 문서를 참고해주시길 부탁드립니다.)

OAuth 2.0 공식 문서

깃허브의 OAuth 인증 활용 가이드
일반적인 OAuth 인증 프로세스 예시

오픈 리다이렉터 공격

오픈 리다이렉터(Open Redirector)는 사용자 클라이언트에 타당성 검증 없이 파라미터값을 리다이렉트하며 조절하는 엔트포인트입니다. 이때, 주고받는 ‘redirect_uri’ 주소에는 인증 서버가 클라이언트에게 발급하는 인증 코드(Authorization Code)와 액세스 토큰(Access Token) 등이 들어있습니다.

사용자가 최초에 클라이언트를 등록할 때, URI를 인증 서버로 전달하면서 인증 서버에서 인증 코드와 액세스 토큰을 받습니다. 이후에는 이 인증 코드와 액세스 토큰만으로 해당 서비스에 계속 접속할 수 있습니다. 그래서 최초 등록시 사용한 URI와 이후에 요청하는 URI가 서로 동일한지 확인하는 검증 절차가 빠져있다면, 공격자가 ‘redirect_uri’ 값을 공격자 서버로 변조해 인증 코드(Authorization Code)와 액세스 토큰(Access Token)을 탈취하는 취약점이 발생합니다.

취약점을 통해 공격자는 서비스에 접속할 수 있는 권한을 탈취했으므로, 사용자 계정 정보 습득 이외에도 서비스 관련 요소에 많은 악영향을 줄 수 있습니다.

Open Redirector 공격 과정

대처 방법

CVE-2019-3778 취약점은 스프링 프레임워크에서 발생하므로, 스프링 공식 공지에 따라 버전 업데이트를 통해서 해당 취약점을 해소할 수 있습니다. 

취약한 버전

취약한 버전: /oauth2/provider/endpoint/DefaultRedirectResolver.java

취약한 버전의 소스코드를 보면, ‘redirectMatches()’에서 등록한 Uri와 요청한 Uri를 인자로 받아 검증합니다. 검증 과정에서 URI PATH를 검증하지 않아 취약점이 발생합니다.

보안 패치 버전

보안 패치를 완료한 버전: /oauth2/provider/endpoint/DefaultRedirectResolver.java

보안 패치를 완료한 소스코드를 보면, ‘redirectMatches()’에서 Path와 Parameter를 검증하는 과정이 추가됐습니다.

안전을 위한 추가 설정 

하지만 위와 같은 상황을 확실하게 방지하기 위해서는, 인증 서버에서 ‘redirect_uri’ 값을 최초 접속뿐 아니라 이후에도 계속 검증(Full Path)해야 합니다.

안전한 설정 예시: AuthorizationServerConfig

‘DefaultRedirectResolver’의 경우, SubDomain에 대한 옵션을 제공하고 있습니다. 이를 통한 악용 가능성을 완전히 제거하기 위해서는 ‘ExactMatchRedirectResolver’를 사용해야 합니다.

도메인만 검증하거나 일부 경로만 검증하도록 간소화해둔 상태라면, 공격자는 언제든지 리다이렉트 취약점을 통해 계속 인증 코드를 탈취할 수 있다는 점을 유념해야 합니다.