인 앱 브라우저의 Google OAuth 로그인 우회기

인앱 WebView에서 차단되는 Google OAuth 로그인을 외부 브라우저로 우회하는 구현 방법.

OAuth, Google, WebView, Frontend

Access blocked: [url]’s request does not comply with Google’s policies.

[url]’s request does not comply with Google’s “Use secure browsers” policy. If this app has a website, you can open a web browser and try signing in from there. If you are attempting to access a wireless network, please follow instructions

You can also contact the developer to let them know their app must comply with Google’s “Use secure browsers” policy.

Learn more about this error.

Error 403: disallowed_useragent

회사에서 프로모션 개발 업무를 진행하면서 알게 되었던 이슈다. 모 url의 요청이 구글의 정책을 준수하지 않아 접근이 불허되었다는 내용이다.

보통 프로모션의 경우, SNS, 커뮤니티 등 다양한 채널과 매체로 전파되고는 한다. 특히 요즘같은 경우 스마트폰의 서드 파티 애플리케이션, 이를테면 카카오톡, 인스타그램, X(ex-Twitter) 등을 통해서도 접하는 경우가 많다.

이들 애플리케이션에서 웹 링크를 접하게 될 경우, 보통 서드 파티 애플리케이션 내의 인 앱 브라우저 환경에서 웹 페이지가 열리게 된다. 이 환경에서 Google OAuth 로그인을 시도할 경우, 위처럼 구글의 정책을 준수하지 않았다며 요청이 거부된다.

Remediation for OAuth via WebView This information is intended for developers with app(s) that use WebViews for authentication. What's happening One or…

support.google.com

위 문서에 따르면, WebView는 기본 브라우저와 동일한 보안 기능을 이용할 수 없으므로 로그인 자격 증명을 훔치거나 악성 코드를 삽입하는 공격에 취약하고, SSO(Single Sign On) 세션에서 사용자의 연결이 끊어지므로 사용자가 Google OAuth를 사용해 다른 앱에 액세스할 때마다 로그인 자격 증명을 다시 입력해야 하는 등, 사용자 경험을 저해시킬 가능성이 존재한다며 개발자가 OAuth 로그인을 위해 Chrome으로 마이그레이션할 것을 권장하고 있다.

따라서 서드 파티 애플리케이션의 WebView 혹은 인 앱 브라우저 내에서 Google OAuth 로그인을 가능케 하는 것은 어려웠다. 대신 Safari, 삼성 인터넷 등의 네이티브 브라우저 혹은 외부 브라우저에서 해당 웹 페이지가 열리도록 하는 것이 UX를 최대한 보장할 수 있는 하나의 방법이라고 판단했다.

그렇다면 외부 브라우저를 열어주어야 했다. 가장 먼저 떠오르는 것은 JavaScript Web API인 window.open(). 그렇지만 이 경우의 수는 정상적으로 동작하지 않는다. 서드 파티 애플리케이션 내의 인 앱 브라우저는 보안 및 기능상의 이유로 window.open() API의 정상적인 동작을 차단시킨다.

인 앱 브라우저는 시스템 리소스 및 사용자 데이터에 대한 액세스를 제한하도록 설계된 샌드박스 환경이다. 이 환경에서 window.open()를 허용할 경우 악성 웹 페이지에서 새 창을 열어 자격 증명을 훔치기 위해 입력을 유도하거나, 인증에 사용되는 세션 쿠키를 훔치려 시도할 수도 있고, 앱의 보안 조치를 우회하려 시도하며 앱의 보안을 손상시킬 수도 있다. 또한, 새 브라우저 창을 만들도록 허용하면 앱 개발자가 의도한 앱 내 사용자 환경이 달라지거나 앱과 충돌이 일어날 수도 있기 때문이다.

그래서 외부 브라우저를 켜기 위한 방법을 찾던 중, LINE에서는 앱에서 외부 브라우저를 여는 방법을 제공하고 있었다. 이를 보고 서드 파티 애플리케이션마다 서로 다른 userAgent를 가지며 이를 통해서 애플리케이션을 구분할 수 있을 것이라 판단했고, 모바일 디바이스에서 주요 애플리케이션의 userAgent를 직접 알아봤다.

- LINE : line - KakaoTalk : kakaotalk - Naver : naver - Instagram : instagram - Telegram : safari (iOS 17.5.1) - X(ex-Twitter) : safari (iOS 17.5.1)

cf. Test Device : iPhone 15 Pro, iOS 17.5.1

서드 파티 애플리케이션마다 서로 다른 userAgent를 갖고 있는 것을 확인했는데, 특이한 점은 텔레그램 및 트위터는 디바이스의 네이티브 브라우저로 나타났다는 점이다. 그래서 텔레그램과 트위터의 경우, 인 앱 브라우저에서의 Google OAuth 로그인 시도가 정책에 위배되지 않고 성공적으로 이루어졌다.

현재 주요 전파 매체로 이용하고 있는 것은 텔레그램, 트위터, 카카오톡이었는데 텔레그램과 트위터의 경우에는 문제가 없었으므로 남은 것은 카카오톡이었다. 카카오 디벨로퍼스에서 해당 정보를 찾을 수 없었지만, 어떤 대단하신 분의 블로그에서 방법을 찾을 수 있었다. kakaotalk Scheme과 함께 보내려는 url을 encodeURIComponent 함수로 감싼 주소로 이동시키면, 감쪽같이 외부 브라우저로 이동하는 것을 확인할 수 있었다.

또한, AOS 디바이스의 경우 자체적으로 Chrome 브라우저를 탑재하고 있기 때문에 다양한 서드 파티 애플리케이션에서도 intent Scheme을 통해서 외부 브라우저를 열어줄 수 있었다.

따라서 Vue의 생명주기 메서드인 onMounted를 통해 해당 페이지가 로드되었을 때, 외부 브라우저에서 열리도록 구현했고, 테스트 결과 성공적으로 카카오톡에서도 외부 브라우저인 Safari나 삼성 인터넷으로 열리는 것을 확인할 수 있었다. React에서도 useEffect 훅을 이용하거나, 특정 이벤트 핸들러를 만들어 컴포넌트에 부착하여 사용할 수 있을 듯 하다.

이를 통해 주요한 채널에 대해서는 처리할 수 있었지만, iOS 디바이스 같은 경우는 엄격한 보안 정책으로 인해 여전히 사각지대가 존재하고, 그렇기 때문에 이것이 완벽한 솔루션이라고 볼 수는 없을 것 같다. 그래서 다른 회사의 제품은 어떻게 해결하고 있는지 찾아보았는데, Instagram의 인 앱 브라우저에서 chatGPT 페이지를 열어 Google OAuth 로그인을 시도했지만 같은 에러 메시지를 확인할 수 있었다.

여태 OAuth와 같은 소셜 로그인의 인증 방법이 보안과 편의성을 모두 챙겼다고 생각하고 있었다. 하지만 ‘은탄은 없다'는 말처럼, 서비스를 개발하며 선택할 수 있는 다양한 도구들 중 이상적인 것은 대개 존재하지 않기 때문에 처한 상황과 보유 자원에 따라 적절한 도구를 선택해야 하고, 이번 이슈와 같은 케이스 스터디를 통해 개발하면서 발생하는 문제들을 예측하고 얼마나 많은 경우를 고려해야 하는지에 대해 깨닫는 계기가 되었다.

References

https://support.google.com/faqs/answer/12284343?hl=en-GB https://aws.amazon.com/ko/what-is/sso/ https://developers.line.biz/en/docs/line-login/using-line-url-scheme/#opening-url-in-external-browser https://burndogfather.com/271


원문: Medium