概要
2022 年 2 月 16 日、Google は、より安全な OAuth フローを使用して Google OAuth のやり取りを安全にする 計画を発表しました。このガイドでは、ループバック IP アドレス フローからサポートされている代替手段に移行するために必要な変更と手順について 説明します。
この取り組みは、Google の OAuth 2.0 認可エンドポイントとのやり取りにおけるフィッシング攻撃やアプリのなりすまし攻撃 に対する保護対策です。
ループバック IP アドレス フローとは
The ループバック IP アドレス フローでは、ユーザーが OAuth 同意リクエストを承認した後に認証情報が送信されるリダイレクト URI のホスト コンポーネントとして、ループバック IP アドレスまたはlocalhost を使用できます。このフローは中間者攻撃に対して脆弱です。一部のオペレーティング システムで同じループバック インターフェースにアクセスする悪意のあるアプリが、指定されたリダイレクト URI への認可サーバーからのレスポンスを傍受して認証コードにアクセスする可能性があります。ループバック IP アドレス フローは、ネイティブの iOS、Android、 Chrome の OAuth クライアント タイプでは非推奨となっていますが、デスクトップ アプリでは引き続きサポートされます。
コンプライアンスの主な日程
- 2022 年 3 月 14 日 - 新しい OAuth クライアントでループバック IP アドレス フロー を使用できなくなります。
- 2022 年 8 月 1 日 - 非準拠の OAuth リクエストに対して、ユーザー向けの警告メッセージが 表示されることがあります。
- 2022 年 8 月 31 日 - ループバック IP アドレス フローがブロックされます 2022 年 3 月 14 日より前に作成されたネイティブの Android、Chrome アプリ、iOS の OAuth クライアントの場合
- 2022 年 10 月 21 日 - 既存のクライアントはすべてブロックされます (除外されたクライアントを含む)。
非準拠のリクエストに対しては、ユーザー向けのエラー メッセージが表示されます。 このメッセージは、Google API Console の OAuth 同意画面で登録したサポート メールアドレスを表示しながら、アプリがブロックされていることをユーザーに伝えます。
- 影響を受けるかどうかを確認します。
- 影響を受ける場合は、サポートされている代替手段に移行します。
影響を受けるかどうかを確認する
OAuth クライアント ID のタイプを確認する
Google Cloud コンソール の [クライアント] ページに移動し、 [OAuth 2.0 クライアント ID] セクションで OAuth クライアント ID のタイプを確認します。次のいずれかになります。 ウェブ アプリケーション、Android、iOS、 ユニバーサル Windows プラットフォーム(UWP)、Chrome アプリ、テレビと入力制限のあるデバイス、 デスクトップ アプリ。
クライアント タイプが Android、Chrome アプリ、または iOS で、 ループバック IP アドレス フローを使用している場合は、 次の手順に進みます。
デスクトップ アプリの OAuth クライアントでループバック IP アドレス フローを使用している場合は、この非推奨化に関連する作業を行う必要はありません。その OAuth クライアント タイプでの使用は引き続きサポートされます。
アプリがループバック IP アドレス フローを使用しているかどうかを確認する方法
アプリのコードまたは 送信ネットワーク呼び出し(アプリが OAuth ライブラリを使用している場合)を調べて、アプリが作成している Google OAuth 認可リクエスト でループバック リダイレクト URI 値が使用されているかどうかを確認します。
アプリケーション コードを確認する
-
アプリケーション コードの Google OAuth 認可エンドポイントを呼び出しているセクションを確認し、
-
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)
redirect_uri パラメータに次のいずれかの値が設定されているかどうかを確認します。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 拡張機能ページに移動する
- 拡張機能ページの右上にある [**デベロッパー モード**] チェックボックスをオンにする
- モニタリングする拡張機能を選択する
- 拡張機能ページの [**ビューを検証**] セクションで [**バックグラウンド ページ**] リンクをクリックする
- A [Developer Tools] popup will open up where you can monitor the ネットワーク トラフィック in the [ Network] tab
- iOS - Instruments で HTTP トラフィックを分析する
- デスクトップ アプリ - アプリの開発に使用したオペレーティング システムで使用できるネットワーク キャプチャ ツールを使用する
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 にアクセスする
クライアントサイド アクセス
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 クライアントをサポートするために、サーバーサイドで Google API にアクセスする方法を示しています。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 ガイドをご覧ください。