环回 IP 地址流程迁移指南

概览

2022 年 2 月 16 日,我们 宣布计划使用更安全的 OAuth 流程,让 Google OAuth 互动更安全。本指南可帮助您了解从环回 IP 地址流程成功迁移到受支持的替代方案所需的更改和步骤。 成功地从环回 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 日 - 禁止所有现有客户端使用环回 IP 地址流程 (包括豁免的客户端)

对于不符合要求的请求,系统会显示面向用户的错误消息。 该消息会向用户说明应用已被禁止,同时显示您在 Google Cloud 控制台的 OAuth 权限请求页面中注册的支持电子邮件地址

如需完成迁移流程,您需要完成以下两个主要步骤:
  1. 确定您是否会受到影响。
  2. 如果会受到影响,请迁移到受支持的替代方案。

确定您是否会受到影响

查看您的 OAuth 客户端 ID 类型

前往 客户端页面,然后在 Google Cloud 控制台的 OAuth 2.0 客户端 ID部分下查看您的 OAuth 客户端 ID 类型。该类型将是以下任一类型:Web 应用AndroidiOS通用 Windows 平台 (UWP)Chrome 应用电视和有限输入设备桌面应用

如果您的客户端类型为 Android、Chrome 应用或 iOS,并且您使用的是环回 IP 地址流程,请继续执行下一步。

如果您在桌面应用 OAuth 客户端上使用 环回 IP 地址流程,则无需执行与此项弃用相关的任何操作,因为系统将继续支持使用该 OAuth 客户端类型 。

如何确定您的应用是否在使用环回 IP 地址流程

检查您的应用代码出站网络调用(如果您的应用使用的是 OAuth 库),以确定您的应用发出的 Google OAuth 授权请求 是否使用了环回重定向 URI 值。

检查您的应用代码

查看应用代码中调用 Google OAuth 授权端点 的部分,并确定 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
环回 IP 地址重定向流程请求的示例类似于以下内容:
https://accounts.google.com/o/oauth2/v2/auth?
redirect_uri=http://localhost:3000&
response_type=code&
scope=<SCOPES>&
state=<STATE>&
client_id=<CLIENT_ID>

检查出站网络调用

检查网络调用的方法因您的 应用客户端类型而异。
在检查网络调用时,查找发送到 Google OAuth 授权端点的请求,并确定 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
环回 IP 地址重定向流程请求的示例类似于以下内容:
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 (AndroidiOS)。

该 SDK 可让您轻松访问 Google API,并处理对 Google 的 OAuth 2.0 授权端点的所有调用。

以下文档链接提供了有关如何使用推荐的 SDK 访问 Google API 而无需使用环回 IP 地址 重定向 URI 的信息。

在 Android 上访问 Google API

客户端访问

以下示例展示了如何 在 Android 上的客户端 访问 Google API,其中使用了推荐的 Google Identity 服务 Android 库。

  List requestedScopes = 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。
  List requestedScopes = 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), 或者将 fetcher 授权方 (GTMFetcherAuthorizationProtocol) 与 适用于 REST 的 Objective-C 的 Google API 客户端库搭配使用。

查看 客户端访问 指南,了解如何在客户端访问 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 指南