架構外 (OOB) 流程遷移指南

透過集合功能整理內容 你可以依據偏好儲存及分類內容。

總覽

我們在 2022 年 2 月 16 日宣布了計畫,讓安全性 OAuth 流程更加安全,以利 Google OAuth 互動。本指南可協助您瞭解必要的變更和步驟,以便成功從 OAuth 頻外 (OOB) 流程遷移至支援的替代方案。

此措施可以有效保護 Google 與 OAuth 2.0 授權端點互動,防範網路詐騙和應用程式冒用他人攻擊的行為。

什麼是 OOB?

OAuth 架構外 (OOB) (也稱為手動複製/貼上選項) 是舊版的流程,適用於在使用者核准 OAuth 同意要求後開發的重新導向用戶端,以沒有憑證 URI 接受憑證。OOB 流程會產生遠端網路詐騙風險,而用戶端必須改用其他替代方案來防範這個安全漏洞。

所有用戶端類型 (即網頁應用程式、Android、iOS、通用 Windows 平台 (UWP)、Chrome 應用程式、電視和受限制的輸入裝置 (電腦版應用程式) 都會淘汰 OOB 流程。

重要法規遵循日期

  • 2022 年 2 月 28 日 - OOB 流程禁止使用新的 OAuth 授權
  • 2022 年 9 月 5 日 - 系統可能會向不符合規定的 OAuth 要求顯示向使用者顯示的警告訊息
  • 2022 年 10 月 3 日:針對 2022 年 2 月 28 日前建立的 OAuth 用戶端,OOB 流程已淘汰
  • 2023 年 1 月 31 日 - 所有現有用戶端均遭到封鎖 (包括排除的客戶)。自 2023 年 1 月 31 日起,用戶端可以要求寄送一次性擴充功能以繼續使用 OOB 流程,如發送給受影響用戶端的電子郵件所述。

系統可能會在一個月前,向不符合規定的要求顯示向使用者顯示的警告訊息,例如在 2022 年 9 月 5 日全面淘汰 OOB 流程。訊息會告知使用者應用程式可能很快就會遭到封鎖,並顯示您在 Google API 控制台的 OAuth 同意畫面中登錄的支援電子郵件。

您可以向授權呼叫傳遞查詢參數,藉此確認向使用者顯示的警告訊息,並隱藏訊息,如下所示:
  • 請前往您應用程式中的程式碼,並將要求傳送至 Google 的 OAuth 2.0 授權端點
  • 在重新導向流程要求中加入值為強制執行日期 2022-10-03 的 ack_oob_shutdown 參數。範例:
    ack_oob_shutdown=2022-10-03
完成遷移程序有兩個主要步驟:
  1. 確認你是否受到影響。
  2. 如果您受到影響,請遷移至更安全的安全性選項。

確認你是否受到影響

這項淘汰措施僅適用於正式版應用程式 (也就是發布狀態設為正式版的應用程式)。針對測試發布狀態的應用程式,流程會繼續運作。

請在「 Google API Console 」的 OAuth Consent Screen page中查看發布狀態,然後在專案中處於「實際運作中」發布狀態中使用 OOB 流程,並繼續進行下一個步驟。

如何判斷應用程式是否使用 OOB 流程

檢查應用程式程式碼傳出網路呼叫 (如果您的應用程式使用 OAuth 程式庫),判斷應用程式發出的 Google OAuth 授權要求是否使用 OOB 重新導向 URI 值。

檢查應用程式程式碼

查看應用程式程式碼的各個部分,並呼叫 Google OAuth 授權端點,並判斷 redirect_uri 參數是否屬於下列任何值:
  • redirect_uri=urn:ietf:wg:oauth:2.0:oob
  • redirect_uri=urn:ietf:wg:oauth:2.0:oob:auto
  • redirect_uri=oob
OOB 重新導向流程要求的範例應如下所示:
https://accounts.google.com/o/oauth2/v2/auth?
response_type=code&
scope=<SCOPES>&
state=<STATE>&
redirect_uri=urn:ietf:wg:oauth:2.0:oob&
client_id=<CLIENT_ID>

檢查撥出電話呼叫

檢查網路呼叫的方法會因應用程式用戶端類型而異。
檢查網路呼叫時,請查看傳送至 Google OAuth 授權端點的要求,並判斷 redirect_uri 參數是否包含以下任一值:
  • redirect_uri=urn:ietf:wg:oauth:2.0:oob
  • redirect_uri=urn:ietf:wg:oauth:2.0:oob:auto
  • redirect_uri=oob
以下列舉 OOB 重新導向流程要求的範例:
https://accounts.google.com/o/oauth2/v2/auth?
response_type=code&
scope=<SCOPES>&
state=<STATE>&
redirect_uri=urn:ietf:wg:oauth:2.0:oob&
client_id=<CLIENT_ID>

遷移至安全的替代方案

行動用戶端 (Android / iOS)

如果您決定應用程式使用 OOB 流程並採用 Android 或 iOS OAuth 用戶端類型,建議您改用 Google 登入行動 SDK (AndroidiOS)。

這個 SDK 可讓您輕鬆存取 Google API,並處理對 Google OAuth 2.0 授權端點的所有呼叫。

請參閱下列說明文件連結,瞭解如何在不使用 OOB 重新導向 URI 的情況下,使用 Google 登入 SDK 存取 Google API。

在 Android 裝置上存取 Google API

伺服器端 (離線) 存取權
以下範例說明如何在 Android 的伺服器端存取 Google API
Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
try {
  GoogleSignInAccount account = task.getResult(ApiException.class);
  
  // request a one-time authorization code that your server exchanges for an
  // access token and sometimes refresh token
  String authCode = account.getServerAuthCode();
  
  // Show signed-in UI
  updateUI(account);

  // TODO(developer): send code to server and exchange for access/refresh/ID tokens
} catch (ApiException e) {
  Log.w(TAG, "Sign-in failed", e);
  updateUI(null);
}

請參閱伺服器端存取權指南,瞭解如何透過伺服器端存取 Google API。

在 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 要求的標題中加入存取權杖,或是透過 REST 適用的 Google API 用戶端程式庫使用擷取器授權者 (GTMFetcherAuthorizationProtocol)。Authorization: Bearer ACCESS_TOKENGTMFetcherAuthorizationProtocol

請參閱用戶端存取權指南,瞭解如何在用戶端存取 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 應用程式用戶端的 OOB 流程,請改用 Chrome Identity API

以下範例說明如何在不使用 OOB 重新導向 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 指南,進一步瞭解如何透過 Chrome Identity API 存取通過驗證的使用者並呼叫 Google 端點。

網頁應用程式

如果您決定讓應用程式在網頁應用程式使用 OOB 流程,請改用 Google API 用戶端程式庫。如需不同程式設計語言的用戶端程式庫,請參閱這篇文章

程式庫可讓您輕鬆存取 Google API,並處理對 Google 端點的所有呼叫。

伺服器端 (離線) 存取權
伺服器端 (離線) 存取模式可讓您執行下列操作:
  • 站在伺服器中定義公開存取的端點 (重新導向 URI),以便接收授權碼。
  • 請在 Google API Console的 Credentials page 中設定重新導向 URI

下列程式碼片段顯示如何使用 Google Drive API 在伺服器端列出使用者的 Google 雲端硬碟檔案,而不需使用 OOB 重新導向 URI。

async function main() {
  const server = http.createServer(async function (req, res) {

  if (req.url.startsWith('/oauth2callback')) {
    let q = url.parse(req.url, true).query;

    if (q.error) {
      console.log('Error:' + q.error);
    } else {
      
      // Get access and refresh tokens (if access_type is offline)
      let { tokens } = await oauth2Client.getToken(q.code);
      oauth2Client.setCredentials(tokens);

      // Example of using Google Drive API to list filenames in user's Drive.
      const drive = google.drive('v3');
      drive.files.list({
        auth: oauth2Client,
        pageSize: 10,
        fields: 'nextPageToken, files(id, name)',
      }, (err1, res1) => {
        // TODO(developer): Handle response / error.
      });
    }
  }
}

請參閱伺服器端網頁應用程式指南,瞭解如何透過伺服器端存取 Google API。

用戶端存取權

下列 JavaScript 程式碼片段示範如何在用戶端上使用 Google API 存取使用者的日曆活動。


// initTokenClient() initializes a new token client with your
// web app's client ID and the scope you need access to

const client = google.accounts.oauth2.initTokenClient({
  client_id: 'YOUR_GOOGLE_CLIENT_ID',
  scope: 'https://www.googleapis.com/auth/calendar.readonly',
  
  // callback function to handle the token response
  callback: (tokenResponse) => {
    if (tokenResponse && tokenResponse.access_token) { 
      gapi.client.setApiKey('YOUR_API_KEY');
      gapi.client.load('calendar', 'v3', listUpcomingEvents);
    }
  },
});

function listUpcomingEvents() {
  gapi.client.calendar.events.list(...);
}

請參閱用戶端網頁應用程式指南,瞭解如何透過用戶端存取 Google API。

電腦版用戶端

如果您決定讓應用程式在桌面用戶端上使用 OOB 流程,請改用迴圈 IP 位址 (localhost127.0.0.1) 流程