概要
2022 年 2 月 16 日、Google は、より安全な OAuth フローを使用して Google OAuth のインタラクションをより安全にするという計画を 発表しました。このガイドでは、ループバック IP アドレス フローからサポートされている代替手段に正常に移行するために必要な変更と手順について説明します。
これは、Google の OAuth 2.0 認可エンドポイントとのやり取り中に発生するフィッシング攻撃やアプリのなりすまし攻撃に対する保護対策です。
ループバック IP アドレスのフローとは
ループバック IP アドレス フローは、ユーザーが OAuth 同意リクエストを承認した後に認証情報が送信されるリダイレクト URI のホスト コンポーネントとして、ループバック IP アドレスまたはlocalhost
の使用をサポートしています。このフローでは、中間攻撃を受けやすくなります。一部のオペレーティング システムで同じループバック インターフェースにアクセスする悪意のあるアプリが、認可サーバーから指定されたリダイレクト 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 Console の OAuth 同意画面で登録したサポート メールアドレスを表示します。
- 影響を受けるかどうかを判断します。
- 影響を受けている場合は、サポートされている代替手段に移行してください。
影響を受けるかどうかを確認する
OAuth クライアント ID のタイプを確認する
の に移動し、[OAuth 2.0 クライアント ID] セクションで 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)
アプリが Android または iOS の OAuth クライアント タイプでループバック IP アドレス フローを使用していることが判明した場合は、推奨される SDK(Android、iOS)に移行する必要があります。
この SDK を使用すると、Google API に簡単にアクセスでき、Google の OAuth 2.0 認可エンドポイントへのすべての呼び出しを処理できます。
以下のドキュメントのリンクには、推奨される SDK を使用して、ループバック IP アドレスのリダイレクト URI を使用せずに Google API にアクセスする方法が記載されています。
Android で Google API にアクセスする
クライアントサイド アクセス
次の例は、推奨される Google Identity Services 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 リクエストのヘッダーにアクセス トークンを含めるか、
Objective-C for REST の Google API クライアント ライブラリで取得元の認証情報(GTMFetcherAuthorizationProtocol
)を使用します。Authorization: Bearer ACCESS_TOKEN
クライアントサイドで 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 ガイドをご覧ください。