概览
我们于 2022 年 2 月 16 日 宣布了以下计划:采用更安全的 OAuth 流程,让 Google OAuth 互动更安全。本指南可帮助您了解从 OAuth 带外 (OOB) 流程成功迁移到受支持的替代方案所需的更改和步骤。
此措施是一种保护措施,可在用户与 Google 的 OAuth 2.0 授权端点互动期间防范钓鱼式攻击和应用冒充攻击。
什么是 OOB?
OAuth 带外 (OOB)(也称为手动复制/粘贴选项)是一种旧流程,旨在支持没有重定向 URI 的原生客户端,以便在用户批准 OAuth 同意请求后接受凭据。OOB 流程会造成远程钓鱼式攻击风险,客户端必须迁移到替代方案来防范此漏洞。我们将针对所有客户端类型弃用 OOB 流程,即 Web 应用、Android、iOS、通用 Windows 平台 (UWP)、Chrome 应用、电视和输入受限的设备、桌面应用。
重要合规日期
- 2022 年 2 月 28 日 - OOB 流程禁止使用新的 OAuth
- 2022 年 9 月 5 日 - 系统可能会向不合规的 OAuth 请求显示一条面向用户的警告消息
- 2022 年 10 月 3 日 - 对于 2022 年 2 月 28 日之前创建的 OAuth 客户端,OOB 流程已废弃
- 2023 年 1 月 31 日 - 所有现有客户端都被屏蔽(包括豁免的客户端)
对于不合规的请求,系统会显示一条向用户显示的错误消息。该消息将告知用户应用已被屏蔽,同时显示您在 Google API 控制台的 OAuth 同意屏幕中注册的支持电子邮件地址。
- 确定您是否受到影响。
- 如果您受到影响,请迁移到更安全的替代方案。
确定您是否受到影响
此弃用仅适用于正式版应用(即发布状态设为 正式版的应用)。该流程将继续适用于处于 测试发布状态的应用。
请在 的 OAuth 中查看发布状态。如果您在发布状态为“正式版”的项目中使用 OOB 流程,请继续执行下一步。
如何确定应用是否在使用 OOB 流程
检查您的应用代码或去电网络调用(如果您的应用使用的是 OAuth 库),确定您的应用发出的 Google OAuth 授权请求是否使用了 OOB 重定向 URI 值。
检查应用代码
redirect_uri
参数是否具有以下任何值:
redirect_uri=urn:ietf:wg:oauth:2.0:oob
redirect_uri=urn:ietf:wg:oauth:2.0:oob:auto
redirect_uri=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>
检查去电网络通话
- Web 应用 - 检查 Chrome 上的网络活动
- Android - 使用 Network Inspector 检查网络流量
-
Chrome 应用
- 前往 Chrome 扩展程序页面
- 选中扩展程序页面右上角的开发者模式复选框
- 选择要监控的扩展程序
- 点击扩展程序页面的 Inspect views 部分中的后台网页链接
- 此时会打开一个开发者工具弹出式窗口,您可以在其中通过 “网络”标签页监控网络流量
- iOS - 使用插桩分析 HTTP 流量
- Universal Windows Platform (UWP) - 在 Visual Studio 中检查网络流量
- 桌面应用 - 使用适用于应用开发的操作系统的 网络捕获工具
redirect_uri
参数是否具有以下任何值:
redirect_uri=urn:ietf:wg:oauth:2.0:oob
redirect_uri=urn:ietf:wg:oauth:2.0:oob:auto
redirect_uri=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)
如果您确定应用使用的是 Android 或 iOS OAuth 客户端类型的 OOB 流程,您应改用我们的 Google 登录移动 SDK(Android、iOS)。
借助该 SDK,您可以轻松访问 Google API,并处理对 Google 的 OAuth 2.0 授权端点的所有调用。
以下文档链接介绍了如何在不使用 OOB 重定向 URI 的情况下使用 Google 登录 SDK 访问 Google API。
访问 Google API (Android)
服务器端(离线)访问
以下示例展示了如何在 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 请求的标头中添加访问令牌 (Authorization: Bearer ACCESS_TOKEN
),或者将提取器授权程序 (GTMFetcherAuthorizationProtocol
) 与
适用于 REST 的 Objective-C 客户端库搭配使用。
请参阅客户端访问指南,了解如何在客户端访问 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 端点。
Web 应用
如果您确定自己的应用使用的是 Web 应用的 OOB 流程,您应改用我们的某个 Google API 客户端库。此处列出了适用于不同编程语言的客户端库。
借助这些库,您可以轻松访问 Google API 并处理对 Google 端点的所有调用。
服务器端(离线)访问
- 建立一个服务器,并定义一个可公开访问的端点(重定向 URI)来接收授权代码。
- 在 的 中配置 重定向 URI
以下代码段展示了一个 NodeJS 示例,展示了如何在不使用 OOB 重定向 URI 的情况下,使用 Google Drive API 在服务器端列出用户的 Google 云端硬盘文件。
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. }); } } }
请参阅 服务器端 Web 应用指南,了解如何从服务器端访问 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(...); }
请参阅 客户端 Web 应用指南,了解如何从客户端访问 Google API。
桌面客户端
如果您确定应用在桌面客户端上使用 OOB 流程,则应改用
环回 IP 地址(localhost
或 127.0.0.1
)流程。