개요
2022년 2월 16일, Google은 더 안전한 OAuth 흐름을 사용하여 Google OAuth 상호작용을 더 안전하게 만들 계획을 발표했습니다. 이 가이드를 통해 루프백 IP 주소 흐름에서 지원되는 대안으로 성공적으로 이전하는 데 필요한 변경사항과 단계를 이해할 수 있습니다.
이는 Google의 OAuth 2.0 승인 엔드포인트와 상호작용하는 동안 피싱 및 앱 명의 도용 공격을 방지하기 위한 조치입니다.
루프백 IP 주소 흐름이란 무엇인가요?
루프백 IP 주소 흐름은 사용자가 OAuth 동의 요청을 승인한 후 사용자 인증 정보가 전송되는 리디렉션 URI의 호스트 구성요소로 루프백 IP 주소 또는localhost
를 사용하는 것을 지원합니다. 이 흐름은 일부 운영체제에서 동일한 루프백 인터페이스에 액세스하는 악의적인 앱이 승인 서버에서 지정된 리디렉션 URI로 전송되는 응답을 가로채 승인 코드에 액세스할 수 있는 중간자 공격에 취약합니다.
루프백 IP 주소 흐름은 네이티브 iOS, Android, Chrome OAuth 클라이언트 유형에서 지원 중단되지만 데스크톱 앱에서는 계속 지원됩니다.
주요 규정 준수 일정
- 2022년 3월 14일 - 새로운 OAuth 클라이언트가 루프백 IP 주소 흐름을 사용하지 못하도록 차단됨
- 2022년 8월 1일 - 규정을 준수하지 않는 OAuth 요청에 사용자 대상 경고 메시지가 표시될 수 있습니다.
- 2022년 8월 31일 - 2022년 3월 14일 전에 생성된 네이티브 Android, Chrome 앱, iOS OAuth 클라이언트의 루프백 IP 주소 흐름이 차단됨
- 2022년 10월 21일 - 모든 기존 고객이 차단됨(예외 고객 포함)
정책을 준수하지 않는 요청에는 사용자에게 표시되는 오류 메시지가 표시됩니다. 이 메시지는 앱이 차단되었음을 사용자에게 전달하는 동시에 Google API Console의 OAuth 동의 화면에 등록한 지원 이메일을 표시합니다.
- 영향을 받는지 확인합니다.
- 영향을 받는 경우 지원되는 대안으로 이전하세요.
영향을 받는지 확인하기
OAuth 클라이언트 ID 유형 검토
의 로 이동하여 OAuth 2.0 클라이언트 ID 섹션에서 OAuth 클라이언트 ID 유형을 확인합니다. 웹 애플리케이션, Android, iOS, 유니버설 Windows 플랫폼 (UWP), Chrome 앱, TV 및 제한된 입력 장치, 데스크톱 앱 중 하나입니다.
클라이언트 유형이 Android, Chrome 앱 또는 iOS이고 루프백 IP 주소 흐름을 사용하는 경우 다음 단계로 진행합니다.
데스크톱 앱 OAuth 클라이언트에서 루프백 IP 주소 흐름을 사용하는 경우 이 지원 중단과 관련하여 취해야 할 조치는 없습니다. 해당 OAuth 클라이언트 유형의 사용은 계속 지원되기 때문입니다.
앱에서 루프백 IP 주소 흐름을 사용하는지 확인하는 방법
앱 코드 또는 발신 네트워크 호출 (앱에서 OAuth 라이브러리를 사용하는 경우)을 검사하여 앱에서 실행하는 Google OAuth 승인 요청이 루프백 리디렉션 URI 값을 사용하는지 확인합니다.
애플리케이션 코드 검사
redirect_uri
매개변수에 다음 값이 있는지 확인합니다.
-
redirect_uri=http://127.0.0.1:<port>
예:redirect_uri=http://127.0.0.1:3000
-
redirect_uri=http://[::1]:<port>
예:redirect_uri=http://[::1]:3000
-
redirect_uri=http://localhost:<port>
예:redirect_uri=http://localhost:3000
https://accounts.google.com/o/oauth2/v2/auth? redirect_uri=http://localhost:3000& response_type=code& scope=<SCOPES>& state=<STATE>& client_id=<CLIENT_ID>
발신 네트워크 호출 검사
- 웹 애플리케이션 - Chrome에서 네트워크 활동 검사
- Android - 네트워크 검사기로 네트워크 트래픽 검사
-
Chrome 앱
- Chrome 확장 프로그램 페이지로 이동합니다.
- 확장 프로그램 페이지의 오른쪽 상단에 있는 개발자 모드 체크박스를 선택합니다.
- 모니터링할 확장 프로그램을 선택합니다.
- 확장 프로그램 페이지의 뷰 검사 섹션에서 백그라운드 페이지 링크를 클릭합니다.
- 네트워크 탭에서 네트워크 트래픽을 모니터링할 수 있는 개발자 도구 팝업이 열립니다.
- iOS - Instruments로 HTTP 트래픽 분석
- 범용 Windows 플랫폼 (UWP) - Visual Studio에서 네트워크 트래픽 검사
- 데스크톱 앱 - 앱이 개발된 운영체제에서 사용할 수 있는 네트워크 캡처 도구 사용
redirect_uri
매개변수에 다음 값이 있는지 확인합니다.
-
redirect_uri=http://127.0.0.1:<port>
예:redirect_uri=http://127.0.0.1:3000
-
redirect_uri=http://[::1]:<port>
예:redirect_uri=http://[::1]:3000
-
redirect_uri=http://localhost:<port>
예:redirect_uri=http://localhost:3000
https://accounts.google.com/o/oauth2/v2/auth? redirect_uri=http://localhost:3000& response_type=code& scope=<SCOPES>& state=<STATE>& client_id=<CLIENT_ID>
지원되는 대안으로 이전
모바일 클라이언트 (Android / iOS)
앱이 Android 또는 iOS OAuth 클라이언트 유형으로 루프백 IP 주소 흐름을 사용하고 있다고 판단되면 권장 SDK(Android, iOS)를 사용하도록 이전해야 합니다.
이 SDK를 사용하면 Google API에 쉽게 액세스할 수 있으며 Google의 OAuth 2.0 승인 엔드포인트에 대한 모든 호출을 처리할 수 있습니다.
아래 문서 링크에서는 권장 SDK를 사용하여 루프백 IP 주소 리디렉션 URI를 사용하지 않고 Google API에 액세스하는 방법을 설명합니다.
Android에서 Google API에 액세스
클라이언트 측 액세스
다음 예에서는 권장 Google ID 서비스 Android 라이브러리를 사용하여 Android의 클라이언트 측에서 Google API에 액세스하는 방법을 보여줍니다.
ListrequestedScopes = Arrays.asList(DriveScopes.DRIVE_APPDATA); AuthorizationRequest authorizationRequest = AuthorizationRequest.builder().setRequestedScopes(requestedScopes).build(); Identity.getAuthorizationClient(activity) .authorize(authorizationRequest) .addOnSuccessListener( authorizationResult -> { if (authorizationResult.hasResolution()) { // Access needs to be granted by the user PendingIntent pendingIntent = authorizationResult.getPendingIntent(); try { startIntentSenderForResult(pendingIntent.getIntentSender(), REQUEST_AUTHORIZE, null, 0, 0, 0, null); } catch (IntentSender.SendIntentException e) { Log.e(TAG, "Couldn't start Authorization UI: " + e.getLocalizedMessage()); } } else { // Access already granted, continue with user action saveToDriveAppFolder(authorizationResult); } }) .addOnFailureListener(e -> Log.e(TAG, "Failed to authorize", e));
정의된 메서드에 authorizationResult
를 전달하여 사용자의 드라이브 폴더에 콘텐츠를 저장합니다. authorizationResult
에는 액세스 토큰을 반환하는
getAccessToken()
메서드가 있습니다.
서버 측 (오프라인) 액세스
다음 예는 Android의 서버 측에서 Google API에 액세스하는 방법을 보여줍니다.ListrequestedScopes = Arrays.asList(DriveScopes.DRIVE_APPDATA); AuthorizationRequest authorizationRequest = AuthorizationRequest.builder() .requestOfflineAccess(webClientId) .setRequestedScopes(requestedScopes) .build(); Identity.getAuthorizationClient(activity) .authorize(authorizationRequest) .addOnSuccessListener( authorizationResult -> { if (authorizationResult.hasResolution()) { // Access needs to be granted by the user PendingIntent pendingIntent = authorizationResult.getPendingIntent(); try { startIntentSenderForResult(pendingIntent.getIntentSender(), REQUEST_AUTHORIZE, null, 0, 0, 0, null); } catch (IntentSender.SendIntentException e) { Log.e(TAG, "Couldn't start Authorization UI: " + e.getLocalizedMessage()); } } else { String authCode = authorizationResult.getServerAuthCode(); } }) .addOnFailureListener(e -> Log.e(TAG, "Failed to authorize", e));
authorizationResult
에는 백엔드로 전송하여 액세스 토큰과 새로고침 토큰을 가져올 수 있는 승인 코드를 반환하는
getServerAuthCode()
메서드가 있습니다.
iOS 앱에서 Google API에 액세스
클라이언트 측 액세스
아래 예는 iOS의 클라이언트 측에서 Google API에 액세스하는 방법을 보여줍니다.
user.authentication.do { authentication, error in guard error == nil else { return } guard let authentication = authentication else { return } // Get the access token to attach it to a REST or gRPC request. let accessToken = authentication.accessToken // Or, get an object that conforms to GTMFetcherAuthorizationProtocol for // use with GTMAppAuth and the Google APIs client library. let authorizer = authentication.fetcherAuthorizer() }
액세스 토큰을 사용하여 API를 호출합니다. REST 또는 gRPC 요청 (Authorization: Bearer ACCESS_TOKEN
)의 헤더에 액세스 토큰을 포함하거나
Objective-C for REST용 Google API 클라이언트 라이브러리와 함께 가져오기 승인자 (GTMFetcherAuthorizationProtocol
)를 사용합니다.
클라이언트 측에서 Google API에 액세스하는 방법은 클라이언트 측 액세스 가이드를 참고하세요. 를 참고하세요.
서버 측 (오프라인) 액세스
아래 예는 서버 측에서 Google API에 액세스하여 iOS 클라이언트를 지원하는 방법을 보여줍니다.GIDSignIn.sharedInstance.signIn(with: signInConfig, presenting: self) { user, error in guard error == nil else { return } guard let user = user else { return } // request a one-time authorization code that your server exchanges for // an access token and refresh token let authCode = user.serverAuthCode }
서버 측에서 Google API에 액세스하는 방법은 서버 측 액세스 가이드를 참고하세요.
Chrome 앱 클라이언트
앱이 Chrome 앱 클라이언트에서 루프백 IP 주소 흐름을 사용하고 있다고 판단되면 Chrome Identity API를 사용하도록 이전해야 합니다.
아래 예는 루프백 IP 주소 리디렉션 URI를 사용하지 않고 모든 사용자 연락처를 가져오는 방법을 보여줍니다.
window.onload = function() { document.querySelector('button').addEventListener('click', function() { // retrieve access token chrome.identity.getAuthToken({interactive: true}, function(token) { // .......... // the example below shows how to use a retrieved access token with an appropriate scope // to call the Google People API contactGroups.get endpoint fetch( 'https://people.googleapis.com/v1/contactGroups/all?maxMembers=20&key=API_KEY', init) .then((response) => response.json()) .then(function(data) { console.log(data) }); }); }); };
Chrome Identity API로 사용자를 인증하고 Google 엔드포인트를 호출하는 방법에 관한 자세한 내용은 Chrome Identity API 가이드를 참고하세요.