總覽
我們在 2022 年 2 月 16 日 宣布,將採用更安全的 OAuth 流程,提升 Google OAuth 互動的安全性。本指南可協助您瞭解必要變更和步驟,順利從迴路 IP 位址流程遷移至支援的替代方案。
這項措施可防範與 Google OAuth 2.0 授權端點互動時,遭到網路釣魚和應用程式冒名攻擊。
什麼是迴路 IP 位址流程?
回送 IP 位址流程支援使用回送 IP 位址或localhost
做為重新導向 URI 的主機元件,使用者核准 OAuth 同意要求後,系統會將憑證傳送至該 URI。這個流程容易遭受中間人攻擊。在某些作業系統上,惡意應用程式可能會存取相同的迴路介面,攔截授權伺服器傳送至指定重新導向 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 控制台的 OAuth 同意畫面中註冊的支援電子郵件地址。
- 判斷您是否受到影響。
- 如果受到影響,請改用支援的替代方案。
判斷是否受到影響
檢查 OAuth 用戶端 ID 類型
前往 Clients page Google Cloud Console ,在「OAuth 2.0 Client IDs」部分下方查看 OAuth 用戶端 ID 類型。可以是下列任一項目:網頁應用程式、Android、iOS、通用 Windows 平台 (UWP)、Chrome 應用程式、電視和有限輸入裝置、電腦應用程式。
如果您的用戶端類型是 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)
如果判斷應用程式是使用迴路 IP 位址流程,且 OAuth 用戶端類型為 Android 或 iOS,請改用建議的 SDK (Android、iOS)。
SDK 可輕鬆存取 Google API,並處理所有對 Google OAuth 2.0 授權端點的呼叫。
如要瞭解如何使用建議的 SDK 存取 Google API,而不使用迴路 IP 位址重新導向 URI,請參閱下列說明文件連結。
在 Android 上存取 Google API
用戶端存取權
以下範例說明如何使用建議的 Google Identity 服務 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
),或是搭配
適用於 REST 的 Objective-C 版 Google API 用戶端程式庫,使用擷取器授權者 (GTMFetcherAuthorizationProtocol
)。
請參閱用戶端存取指南,瞭解如何在用戶端存取 Google API。說明如何從用戶端存取 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 指南。