Руководство по переходу с внеполосного метода (OOB)

Обзор

16 февраля 2022 г. мы объявили о планах повысить безопасность взаимодействий с Google OAuth за счет использования более защищенных потоков OAuth. В этом руководстве рассказывается, как перейти с OAuth OOB на поддерживаемые альтернативы.

Это защитная мера против фишинга и атак с имитацией приложений при взаимодействии с конечными точками авторизации OAuth 2.0 от Google.

Что такое OOB?

Внеполосный (OOB) поток OAuth, также известный как ручное копирование и вставка, – это устаревший поток, разработанный для поддержки установленных клиентов, у которых нет URI перенаправления для приема учетных данных после того, как пользователь одобрит запрос согласия OAuth. Процесс OOB создает риск удаленного фишинга, и клиенты должны перейти на альтернативный метод, чтобы защититься от этой уязвимости.

Процесс OOB будет отключен для всех типов приложений, включая веб-приложения, приложения для Android, iOS, универсальной платформы Windows (UWP), Chrome, телевизоров и устройств с ограниченными возможностями ввода, а также компьютерные приложения.

Ключевые даты

  • 28 февраля 2022 г. – блокировка новых способов использования OAuth для OOB.
  • 5 сентября 2022 г. – для запросов OAuth, не соответствующих требованиям, может показываться пользовательское предупреждение.
  • 3 октября 2022 г. – поддержка OOB-процесса прекращена для клиентов OAuth, созданных до 28 февраля 2022 г.
  • 31 января 2023 г. – блокировка всех существующих клиентов (включая исключения).

Для запросов, не соответствующих требованиям, будет отображаться пользовательское сообщение об ошибке. В сообщении будет указано, что приложение заблокировано, а также будет показан адрес электронной почты службы поддержки, который вы зарегистрировали в окне запроса доступа OAuth в консоли Google Cloud.

Чтобы завершить процесс перехода, выполните следующие действия:

  1. Определите, затронет ли вас это изменение.
  2. Если вы используете этот фреймворк, перейдите на более безопасный способ авторизации.

Как определить, затронет ли вас это изменение

Это изменение касается только рабочих приложений, то есть тех, у которых статус публикации – В рабочей версии. Для приложений со статусом публикации Тестирование процесс останется прежним.

Проверьте статус публикации в OAuth на странице Брендинг в консоли Google Cloud. Если вы используете поток OOB в проекте со статусом "In Production", перейдите к следующему шагу.

Как определить, использует ли ваше приложение OOB-процесс

Проверьте код приложения или исходящий сетевой вызов (если в приложении используется библиотека OAuth), чтобы определить, используется ли в запросе авторизации Google OAuth, который отправляет ваше приложение, значение URI перенаправления OOB.

Проверьте код приложения

Проверьте раздел кода приложения, в котором вы вызываете конечные точки авторизации 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

Пример запроса для переадресации вне браузера:

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

Пример запроса для переадресации вне браузера:

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-процесс с типом приложения OAuth для Android или iOS, вам следует перейти на рекомендуемые SDK (Android, iOS).

SDK помогает получить доступ к API Google и обрабатывает все вызовы конечных точек авторизации OAuth 2.0.

В документации по ссылкам ниже рассказывается, как использовать рекомендуемые SDK для доступа к Google API без URI перенаправления OOB.

Доступ к API Google на Android

Клиентский доступ

В примере ниже показано, как получить доступ к API Google на стороне клиента в Android с помощью рекомендуемой библиотеки сервисов идентификации Google для Android.

List<Scopes> 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(), который возвращает токен доступа.

Доступ на стороне сервера (офлайн)

В примере ниже показано, как получить доступ к API Google на стороне сервера в Android.

List<Scopes> 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(), который возвращает код авторизации. Его можно отправить в серверную часть, чтобы получить токен доступа и токен обновления.

Как получить доступ к API Google в приложении для iOS

Клиентский доступ

В примере ниже показано, как получить доступ к API Google на стороне клиента в iOS.

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 <var>ACCESS_TOKEN</var>) или используя авторизатор средства извлечения (GTMFetcherAuthorizationProtocol) с клиентской библиотекой API Google для Objective-C для REST.

Ознакомьтесь с руководством по клиентскому доступу, чтобы узнать, как получить доступ к API Google на стороне клиента.

Доступ на стороне сервера (офлайн)

В следующем примере показано, как получить доступ к API Google на стороне сервера для поддержки клиента 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
}

Ознакомьтесь с руководством по доступу на стороне сервера, чтобы узнать, как получить доступ к API Google на стороне сервера.

Клиент приложения Chrome

Если вы обнаружите, что ваше приложение использует OOB-процесс в клиенте приложения Chrome, перейдите на Chrome Identity API.

В примере ниже показано, как получить все контакты пользователя без использования URI переадресации OOB.

window.onload = function() {
  document.querySelector('button').addEventListener('click', function() {

  
  // retrieve access token
  chrome.identity.getAuthToken({interactive: true}, function(token) {
  
  // ..........


  // the following example 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)
    });
   });
 });
};

Дополнительную информацию о том, как аутентифицировать пользователей и вызывать конечные точки Google с помощью Chrome Identity API, можно найти в руководстве по Chrome Identity API.

Веб-приложение

Если вы обнаружите, что ваше веб-приложение использует OOB, перейдите на одну из клиентских библиотек Google API. Ознакомьтесь со списком клиентских библиотек Google API для разных языков программирования.

Библиотеки упрощают доступ к API Google и обрабатывают все вызовы конечных точек Google.

Доступ на стороне сервера (офлайн)

Чтобы использовать режим доступа на стороне сервера (офлайн), выполните следующие действия :

  • Настройте сервер и определите общедоступную конечную точку (URI перенаправления) для получения кода авторизации.
  • Настройте URI переадресации на странице Клиенты в консоли Google Cloud.

В приведенном ниже фрагменте кода показано, как использовать Google Drive API в NodeJS, чтобы получить список файлов пользователя на Google Диске на стороне сервера без использования URI перенаправления OOB.

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.
      });
    }
  }
}

Ознакомьтесь с руководством по веб-приложениям на стороне сервера, чтобы узнать, как получить доступ к API Google со стороны сервера.

Клиентский доступ

В следующем фрагменте кода на 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(...);
}

Ознакомьтесь с руководством по клиентским веб-приложениям, чтобы узнать, как получить доступ к API Google со стороны клиента.

Клиент для ПК

Если вы обнаружите, что ваше приложение использует OOB-авторизацию на клиенте для компьютеров, вам следует перейти на авторизацию с замыканием IP-адреса на себя (localhost или 127.0.0.1).