Как защитить аккаунты пользователей с помощью защиты связанных аккаунтов

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

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

Чтобы помочь вам снизить потенциальный риск таких событий, Google отправляет вашему сервису объекты, называемые токенами событий безопасности. Эти токены содержат минимум информации – только тип события безопасности, время его возникновения и идентификатор затронутого пользователя. Однако этого достаточно, чтобы принять необходимые меры. Например, если аккаунт Google пользователя был взломан, вы можете временно отключить для него функцию "Войти с аккаунтом Google" и запретить отправку писем для восстановления доступа к аккаунту на адрес Gmail пользователя.

Защита связанных аккаунтов основана на стандарте RISC, разработанном фондом OpenID Foundation.

Обзор

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

  1. Настройте проект в API Console.

  2. Создайте конечную точку получателя событий, в которую Google будет отправлять токены событий безопасности. Эта конечная точка отвечает за проверку получаемых токенов и реагирование на события безопасности выбранным вами способом.

  3. Зарегистрируйте конечную точку в Google, чтобы начать получать токены событий безопасности.

Подготовка

Вы будете получать токены событий безопасности только для пользователей Google, которые разрешили вашему сервису доступ к информации профиля или адресам электронной почты. Чтобы получить это разрешение, запросите область действия profile или email. Новый SDK Войти с аккаунтом Google и устаревший SDK Вход через Google запрашивают эти области действия по умолчанию. Если вы не используете настройки по умолчанию или напрямую обращаетесь к конечной точке OpenID Connect Google, убедитесь, что запрашиваете хотя бы одну из этих областей действия.

Как настроить проект в API Console

Чтобы начать получать токены событий безопасности, создайте сервисный аккаунт и включите RISC API в проекте API Console. Вы должны использовать тот же проект API Console, который используется для доступа к сервисам Google, например к функции "Войти с аккаунтом Google", в вашем приложении.

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

  1. Откройте страницу Credentials (Учетные данные) в API Console. При появлении запрос�� выберите проект API Console, который вы используете для доступа к сервисам Google в своем приложении.

  2. Нажмите Create credentials (Создать учетные данные) > Service account (Сервисный аккаунт).

  3. Создайте сервисный аккаунт с ролью администратора конфигурации RISC (roles/riscconfigs.admin), следуя этим инструкциям.

  4. Если в вашей организации Google Cloud разрешено создавать ключи сервисных аккаунтов и вы планируете подписывать JWT локально, создайте ключ для нового сервисного аккаунта. Выберите тип ключа JSON и нажмите Create (Создать). После создания ключа вы скачаете JSON-файл с учетными данными сервисного аккаунта. Храните этот файл в безопасном месте, доступном для конечной точки получателя событий.

На странице "Учетные данные" также запишите идентификаторы клиентов, которые вы используете для функции "Войти с аккаунтом Google" или устаревшей функции "Вход через аккаунт Google". Обыч��о ��ля к��ж��о�� ��о��держиваемой платформы используется отдельный идентификатор клиента. Эти идентификаторы клиентов понадобятся вам для проверки токенов событий безопасности, как описано в следующем разделе.

Чтобы включить RISC API, выполните следующие действия:

  1. Откройте страницу RISC API в API Console. Убедитесь, что выбран проект, который вы используете для доступа к сервисам Google.

  2. Прочитайте Условия использования RISC и убедитесь, что вы понимаете требования.

    Если вы включаете API для проекта, принадлежащего организации, убедитесь, что у вас есть полномочия связывать организацию Условиями использования RISC.

  3. Нажмите Включить, только если вы согласны с Условиями RISC.

Создайте конечную точку получателя событий

Чтобы получать уведомления о событиях безопасности от Google, создайте конечную точку HTTPS, которая обрабатывает запросы HTTPS POST. После регистрации конечной точки (см. ниже) Google начнет отправлять на нее криптографически подписанные строки, называемые токенами событий безопасности. Токены событий безопасности – это подписанные JWT, которые содержат информацию об одном событии, связанном с безопасностью.

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

1. Декодирование и проверка токена события безопасности

Поскольку токены событий безопасности – это особый вид JWT, для их декодирования и проверки можно использовать любую библиотеку JWT, например одну из перечисленных на сайте jwt.io. Независимо от того, какую библиотеку вы используете, код проверки токена должен выполнять следующие действия:

  1. Получите идентификатор издателя защиты связанных аккаунтов (issuer) и URI сертификата ключа подписи (jwks_uri) из документа конфигурации RISC от Google, который можно найти по адресу https://accounts.google.com/.well-known/risc-configuration.
  2. С помощью выбранной библиотеки JWT получите идентификатор ключа подписи из заголовка токена события безопасности.
  3. Из документа сертификата ключа подписи Google получите открытый ключ с идентификатором, полученным на предыдущем шаге. Если в документе нет ключа с нужным идентификатором, скорее всего, токен события безопасности недействителен и конечная точка должна вернуть ошибку HTTP 400.
  4. Используя выбранную вами библиотеку JWT, проверьте следующее:
    • Токен события безопасности подписывается с помощью открытого ключа, полученного на предыдущем шаге.
    • Утверждение aud токена – это один из идентификаторов клиента ваших приложений.
    • Значение iss в токене совпадает с идентификатором издателя, полученным из discovery-документа RISC. Обратите внимание, что вам не нужно проверять срок действия токена (exp), поскольку токены событий безопасности представляют собой исторические события и не имеют срока действия.

Пример:

Java

С помощью java-jwt и jwks-rsa-java:

public DecodedJWT validateSecurityEventToken(String token) {
    DecodedJWT jwt = null;
    try {
        // In a real implementation, get these values from
        // https://accounts.google.com/.well-known/risc-configuration
        String issuer = "accounts.google.com";
        String jwksUri = "https://www.googleapis.com/oauth2/v3/certs";

        // Get the ID of the key used to sign the token.
        DecodedJWT unverifiedJwt = JWT.decode(token);
        String keyId = unverifiedJwt.getKeyId();

        // Get the public key from Google.
        JwkProvider googleCerts = new UrlJwkProvider(new URL(jwksUri), null, null);
        PublicKey publicKey = googleCerts.get(keyId).getPublicKey();

        // Verify and decode the token.
        Algorithm rsa = Algorithm.RSA256((RSAPublicKey) publicKey, null);
        JWTVerifier verifier = JWT.require(rsa)
                .withIssuer(issuer)
                // Get your apps' client IDs from the API console:
                // https://console.developers.google.com/apis/credentials?project=_
                .withAudience("123456789-abcedfgh.apps.googleusercontent.com",
                              "123456789-ijklmnop.apps.googleusercontent.com",
                              "123456789-qrstuvwx.apps.googleusercontent.com")
                .acceptLeeway(Long.MAX_VALUE)  // Don't check for expiration.
                .build();
        jwt = verifier.verify(token);
    } catch (JwkException e) {
        // Key not found. Return HTTP 400.
    } catch (InvalidClaimException e) {

    } catch (JWTDecodeException exception) {
        // Malformed token. Return HTTP 400.
    } catch (MalformedURLException e) {
        // Invalid JWKS URI.
    }
    return jwt;
}

Python

import json
import jwt       # pip install pyjwt
import requests  # pip install requests

def validate_security_token(token, client_ids):
    # Get Google's RISC configuration.
    risc_config_uri = 'https://accounts.google.com/.well-known/risc-configuration'
    risc_config = requests.get(risc_config_uri).json()

    # Get the public key used to sign the token.
    google_certs = requests.get(risc_config['jwks_uri']).json()
    jwt_header = jwt.get_unverified_header(token)
    key_id = jwt_header['kid']
    public_key = None
    for key in google_certs['keys']:
        if key['kid'] == key_id:
            public_key = jwt.algorithms.RSAAlgorithm.from_jwk(json.dumps(key))
    if not public_key:
        raise Exception('Public key certificate not found.')
        # In this situation, return HTTP 400

    # Decode the token, validating its signature, audience, and issuer.
    try:
        token_data = jwt.decode(token, public_key, algorithms='RS256',
                                options={'verify_exp': False},
                                audience=client_ids, issuer=risc_config['issuer'])
    except:
        raise
        # Validation failed. Return HTTP 400.
    return token_data

# Get your apps' client IDs from the API console:
# https://console.developers.google.com/apis/credentials?project=_
client_ids = ['123456789-abcedfgh.apps.googleusercontent.com',
              '123456789-ijklmnop.apps.googleusercontent.com',
              '123456789-qrstuvwx.apps.googleusercontent.com']
token_data = validate_security_token(token, client_ids)

Если токен действителен и был успешно декодирован, возвращается статус HTTP 202. Затем обработайте событие безопасности, указанное в токене.

2. Обработка событий безопасности

После декодирования токен события безопасности выглядит следующим образом:

{
  "iss": "https://accounts.google.com/",
  "aud": "123456789-abcedfgh.apps.googleusercontent.com",
  "iat": 1508184845,
  "jti": "756E69717565206964656E746966696572",
  "events": {
    "https://schemas.openid.net/secevent/risc/event-type/account-disabled": {
      "subject": {
        "subject_type": "iss-sub",
        "iss": "https://accounts.google.com/",
        "sub": "7375626A656374"
      },
      "reason": "hijacking"
    }
  }
}

Утверждения iss и aud указывают на издателя токена (Google) и его предполагаемого получателя (ваш сервис). Вы подтвердили эти утверждения на предыдущем шаге.

Утверждение jti – это строка, которая идентифицирует одно событие безопасности и является уникальной для потока. С помощью этого идентификатора можно отслеживать, какие события безопасности вы получили.

Утверждение events содержит информацию о событии безопасности, которое представляет токен. Это утверждение сопоставляет идентификатор типа события с утверждением subject, которое указывает пользователя, связанного с этим событием, и любые дополнительные сведения о событии, которые могут быть доступны.

Утверждение subject идентифицирует конкретного пользователя по уникальному идентификатору аккаунта Google (sub). Этот идентификатор аккаунта Google совпадает с идентификатором (sub), содержащимся в токенах идентификации JWT, которые выдаются новой библиотекой "Войти с аккаунтом Google" (Javascript, HTML), устаревшей библиотекой Google Sign-In или OpenID Connect. Если subject_type утверждения – id_token_claims, оно также может включать поле email с адресом электронной почты пользователя.

Используйте информацию в утверждении events, чтобы предпринять необходимые действия для типа события в аккаунте указанного пользователя.

Идентификаторы токенов OAuth

Для событий OAuth, связанных с отдельными токенами, тип идентификатора token subject содержит следующие поля:

  • token_type: поддерживается только refresh_token.

  • token_identifier_alg – возможные значения приведены в таблице ниже.

  • token: см. таблицу ниже.

token_identifier_alg токен
prefix Первые 16 символов токена.
hash_base64_sha512_sha512 Двойной хеш токена, полученный с помощью алгоритма SHA-512.

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

Поддерживаемые типы событий

Защита связанных аккаунтов поддерживает следующие типы событий безопасности:

Тип события Атрибуты Как ответить
https://schemas.openid.net/secevent/risc/event-type/sessions-revoked Обязательно. Защитите аккаунт пользователя, завершив все открытые сеансы.
https://schemas.openid.net/secevent/oauth/event-type/tokens-revoked

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

Рекомендуется. Если токен предназначен для доступа к другим API Google, удалите все сохраненные токены OAuth пользователя.

https://schemas.openid.net/secevent/oauth/event-type/token-revoked Идентификаторы токенов приведены в разделе Идентификаторы токенов OAuth.

Обязательно. Если вы храните соответствующий токен ��б��ов��ения, ��далите ��го �� по��росите пользователя повторно дать согласие, когда в следующий раз потребуется токен доступа.

https://schemas.openid.net/secevent/risc/event-type/account-disabled reason=hijacking,
reason=bulk-account

Обязательно. Если аккаунт был отключен по причине hijacking, защитите его, завершив все открытые сеансы.

Рекомендуемый текст. Если аккаунт был отключен по причине bulk-account, проанализируйте действия пользователя в вашем сервисе и определите, какие меры следует принять.

Рекомендуемое действие. Если причина не указана, отключите для пользователя функцию "Вход с аккаунтом Google" и запретите восстановление доступа к аккаунту с помощью адреса электронной почты, связанного с аккаунтом Google пользователя (обычно это аккаунт Gmail, но не обязательно). Предложите пользователю альтернативный способ входа.

https://schemas.openid.net/secevent/risc/event-type/account-enabled Рекомендуется повторно включить вход с аккаунтом Google для пользователя и повторно включить восстановление доступа к аккаунту с помощью адреса электронной почты аккаунта Google пользователя.
https://schemas.openid.net/secevent/risc/event-type/account-credential-change-required Рекомендуется. Следите за подозрительными действиями в сервисе и принимайте необходимые меры.
https://schemas.openid.net/secevent/risc/event-type/verification state=state Рекомендуется регистрировать получение тестового токена.

Повторяющиеся и пропущенные события

Защита связанных аккаунтов попытается повторно отправить события, которые, по ее мнению, не были доставлены. Поэтому иногда вы можете получать одно и то же событие несколько раз. Если это может привести к повторным действиям, которые неудобны для пользователей, попробуйте использовать утверждение jti (уникальный идентификатор события), чтобы дедуплицировать события. Для выполнения потока данных с дедупликацией можно использовать внешние инструменты, например Google Cloud Dataflow.

Обратите внимание, что события доставляются с ограниченным количеством повторных попыток, поэтому, если ваш получатель не работает в течение длитель��ого периода времени, вы можете навсегда пропустить некоторые события.

Зарегистрируйте приемник

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

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

1. Как создать токен авторизации

Вы можете сгенерировать токен авторизации для RISC API, используя Google Cloud CLI (gcloud) с олицетворением сервисного аккаунта (рекомендуется, если применяется iam.disableServiceAccountKeyCreation или для однократной настройки CLI), или подписав JWT локально с помощью закрытого ключа сервисного аккаунта.

Вариант А. Создайте токен доступа с ограниченным сроком действия с помощью gcloud (ключ JSON не требуется)

Если у вашего аккаунта пользователя есть роль "Создатель токенов сервисных аккаунтов" (roles/iam.serviceAccountTokenCreator) в сервисном аккаунте, вы можете создать краткосрочный токен доступа OAuth 2.0 с нужной областью конфигурации RISC прямо в терминале:

AUTH_TOKEN=$(gcloud auth print-access-token \
  --impersonate-service-account=SERVICE_ACCOUNT_EMAIL \
  --scopes=https://www.googleapis.com/auth/risc.configuration.readwrite,https://www.googleapis.com/auth/risc.verify,https://www.googleapis.com/auth/risc.status.readwrite)

Подробнее об областях действия токенов доступа…

Вариант Б. Создание самозаверяющегося JWT с помощью ключа сервисного аккаунта

Чтобы создать токен авторизации локально без сетевого обмена данными, создайте JWT со следующими утверждениями:

{
  "iss": SERVICE_ACCOUNT_EMAIL,
  "sub": SERVICE_ACCOUNT_EMAIL,
  "aud": "https://risc.googleapis.com/google.identity.risc.v1beta.RiscManagementService",
  "iat": CURRENT_TIME,
  "exp": CURRENT_TIME + 3600
}

Подпишите JWT с помощью закрытого ключа сервисного аккаунта, который можно найти в файле JSON, скачанном при создании ключа сервисного аккаунта.

Пример:

Java

С помощью java-jwt и библиотеки аутентификации Google:

public static String makeBearerToken() {
    String token = null;
    try {
        // Get signing key and client email address.
        FileInputStream is = new FileInputStream("your-service-account-credentials.json");
        ServiceAccountCredentials credentials =
               (ServiceAccountCredentials) GoogleCredentials.fromStream(is);
        PrivateKey privateKey = credentials.getPrivateKey();
        String keyId = credentials.getPrivateKeyId();
        String clientEmail = credentials.getClientEmail();

        // Token must expire in exactly one hour.
        Date issuedAt = new Date();
        Date expiresAt = new Date(issuedAt.getTime() + 3600000);

        // Create signed token.
        Algorithm rsaKey = Algorithm.RSA256(null, (RSAPrivateKey) privateKey);
        token = JWT.create()
                .withIssuer(clientEmail)
                .withSubject(clientEmail)
                .withAudience("https://risc.googleapis.com/google.identity.risc.v1beta.RiscManagementService")
                .withIssuedAt(issuedAt)
                .withExpiresAt(expiresAt)
                .withKeyId(keyId)
                .sign(rsaKey);
    } catch (ClassCastException e) {
        // Credentials file doesn't contain a service account key.
    } catch (IOException e) {
        // Credentials file couldn't be loaded.
    }
    return token;
}

Python

import json
import time

import jwt  # pip install pyjwt

def make_bearer_token(credentials_file):
    with open(credentials_file) as service_json:
        service_account = json.load(service_json)
        issuer = service_account['client_email']
        subject = service_account['client_email']
        private_key_id = service_account['private_key_id']
        private_key = service_account['private_key']
    issued_at = int(time.time())
    expires_at = issued_at + 3600
    payload = {'iss': issuer,
               'sub': subject,
               'aud': 'https://risc.googleapis.com/google.identity.risc.v1beta.RiscManagementService',
               'iat': issued_at,
               'exp': expires_at}
    encoded = jwt.encode(payload, private_key, algorithm='RS256',
                         headers={'kid': private_key_id})
    return encoded

auth_token = make_bearer_token('your-service-account-credentials.json')

Этот токен авторизации можно использовать для вызовов RISC API в течение одного часа. Когда срок действия токена истечет, сгенерируйте новый, чтобы продолжить вызовы RISC API.

2. Вызовите API конфигурации потока RISC

Получив токен авторизации, вы можете использовать RISC API для настройки потока событий безопасности вашего проекта, включая регистрацию конечной точки получателя.

Для этого отправьте запрос HTTPS POST на адрес https://risc.googleapis.com/v1beta/stream:update, указав конечную точку получателя и типы событий безопасности, которые вас интересуют:

POST /v1beta/stream:update HTTP/1.1
Host: risc.googleapis.com
Authorization: Bearer AUTH_TOKEN

{
  "delivery": {
    "delivery_method":
      "https://schemas.openid.net/secevent/risc/delivery-method/push",
    "url": RECEIVER_ENDPOINT
  },
  "events_requested": [
    SECURITY_EVENT_TYPES
  ]
}

Пример:

Java

public static void configureEventStream(final String receiverEndpoint,
                                        final List<String> eventsRequested,
                                        String authToken) throws IOException {
    ObjectMapper jsonMapper = new ObjectMapper();
    String streamConfig = jsonMapper.writeValueAsString(new Object() {
        public Object delivery = new Object() {
            public String delivery_method =
                    "https://schemas.openid.net/secevent/risc/delivery-method/push";
            public String url = receiverEndpoint;
        };
        public List<String> events_requested = eventsRequested;
    });

    HttpPost updateRequest = new HttpPost("https://risc.googleapis.com/v1beta/stream:update");
    updateRequest.addHeader("Content-Type", "application/json");
    updateRequest.addHeader("Authorization", "Bearer " + authToken);
    updateRequest.setEntity(new StringEntity(streamConfig));

    HttpResponse updateResponse = new DefaultHttpClient().execute(updateRequest);
    Header[] responseContentTypeHeaders = updateResponse.getHeaders("Content-Type");
    StatusLine responseStatus = updateResponse.getStatusLine();
    int statusCode = responseStatus.getStatusCode();
    HttpEntity entity = updateResponse.getEntity();
    // Now handle response
}

// ...

configureEventStream(
        "https://your-service.example.com/security-event-receiver",
        Arrays.asList(
                "https://schemas.openid.net/secevent/risc/event-type/account-credential-change-required",
                "https://schemas.openid.net/secevent/risc/event-type/account-disabled"),
        authToken);

Python

import requests

def configure_event_stream(auth_token, receiver_endpoint, events_requested):
    stream_update_endpoint = 'https://risc.googleapis.com/v1beta/stream:update'
    headers = {'Authorization': 'Bearer {}'.format(auth_token)}
    stream_cfg = {'delivery': {'delivery_method': 'https://schemas.openid.net/secevent/risc/delivery-method/push',
                               'url': receiver_endpoint},
                  'events_requested': events_requested}
    response = requests.post(stream_update_endpoint, json=stream_cfg, headers=headers)
    response.raise_for_status()  # Raise exception for unsuccessful requests

configure_event_stream(auth_token, 'https://your-service.example.com/security-event-receiver',
                       ['https://schemas.openid.net/secevent/risc/event-type/account-credential-change-required',
                        'https://schemas.openid.net/secevent/risc/event-type/account-disabled'])

Если запрос возвращает HTTP 200, поток событий был успешно настроен и ваша конечная точка получателя должна начать получать токены событий безопасности. В следующем разделе описано, как протестировать конфигурацию потока и конечную точку, чтобы убедиться, что все работает правильно.

Получение и обновление текущей конфигурации потока

Если в будущем вы захотите изменить конфигурацию потока, отправьте авторизованный GET-запрос на адрес https://risc.googleapis.com/v1beta/stream, чтобы получить текущую конфигурацию, измените тело ответа и отправьте измененную конфигурацию обратно на адрес https://risc.googleapis.com/v1beta/stream:update, как описано выше.

Остановить и возобновить поток событий

Если вам потребуется остановить поток событий от Google, отправьте авторизованный запрос POST на адрес https://risc.googleapis.com/v1beta/stream/status:update, указав в теле запроса { "status": "disabled" }. Пока поток отключен, Google не отправляет события на вашу конечную точку и не буферизует события безопасности при их возникновении. Чтобы снова включить поток событий, отправьте POST-запрос { "status": "enabled" } в ту же конечную точку.

3. Необязательно. Протестируйте конфигурацию потока

Чтобы проверить, правильно ли работают вместе конфигурация потока и конечная точка получателя, отправьте токен подтверждения через поток событий. Этот токен может содержать уникальную строку, с помощью которой можно проверить, что токен был получен на вашей конечной точке. Чтобы использовать этот процесс, при регистрации получателя подпишитесь на тип события https://schemas.openid.net/secevent/risc/event-type/verification.

Чтобы запросить токен подтверждения, отправьте авторизованный запрос HTTPS POST на адрес https://risc.googleapis.com/v1beta/stream:verify. В теле запроса укажите идентификационную строку:

{
  "state": "ANYTHING"
}

Пример:

Java

public static void testEventStream(final String stateString,
                                   String authToken) throws IOException {
    ObjectMapper jsonMapper = new ObjectMapper();
    String json = jsonMapper.writeValueAsString(new Object() {
        public String state = stateString;
    });

    HttpPost updateRequest = new HttpPost("https://risc.googleapis.com/v1beta/stream:verify");
    updateRequest.addHeader("Content-Type", "application/json");
    updateRequest.addHeader("Authorization", "Bearer " + authToken);
    updateRequest.setEntity(new StringEntity(json));

    HttpResponse updateResponse = new DefaultHttpClient().execute(updateRequest);
    Header[] responseContentTypeHeaders = updateResponse.getHeaders("Content-Type");
    StatusLine responseStatus = updateResponse.getStatusLine();
    int statusCode = responseStatus.getStatusCode();
    HttpEntity entity = updateResponse.getEntity();
    // Now handle response
}

// ...

testEventStream("Test token requested at " + new Date().toString(), authToken);

Python

import requests
import time

def test_event_stream(auth_token, nonce):
    stream_verify_endpoint = 'https://risc.googleapis.com/v1beta/stream:verify'
    headers = {'Authorization': 'Bearer {}'.format(auth_token)}
    state = {'state': nonce}
    response = requests.post(stream_verify_endpoint, json=state, headers=headers)
    response.raise_for_status()  # Raise exception for unsuccessful requests

test_event_stream(auth_token, 'Test token requested at {}'.format(time.ctime()))

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

Справка по кодам ошибок

RISC API может возвращать следующие ошибки:

Код ошибки Сообщение об ошибке Рекомендуемые действия
400 Конфигурация потока должна содержать поле $fieldname. Ваш запрос к конечной точке https://risc.googleapis.com/v1beta/stream:update недействителен или не может быть обработан. Добавьте в запрос поле $fieldname.
401 Доступ запрещен: Ошибка авторизации. Убедитесь, что вы прикрепили к запросу токен авторизации и что он действителен и не просрочен.
403 Конечная точка доставки должна быть URL с протоколом HTTPS. Конечная точка доставки (т.е. конечная точка, в которую должны доставляться события RISC) должна использовать протокол HTTPS. Мы не отправляем события RISC на URL с протоколом HTTP.
403 В существующей конфигурации потока нет метода доставки, соответствующего спецификации RISC. В вашем облачном проекте Google Cloud уже должна быть конфигурация RISC. Если вы используете Firebase и у вас включена функция "Войти с аккаунтом Google", то Firebase будет управлять RISC для вашего проекта. Вы не сможете создать собственную конфигурацию. Если вы не используете вход с аккаунтом Google для проекта Firebase, отключите его и попробуйте обновить проект через час.
403 Не удалось найти проект. Убедитесь, что вы используете правильный сервисный аккаунт для нужного проекта. Возможно, вы используете сервисный аккаунт, связанный с удаленным проектом. Подробнее о том, как посмотреть все сервисные аккаунты, связанные с проектом…
403 Сервисному аккаунту требуется разрешение на доступ к вашей конфигурации RISC. Перейдите в API Console проекта и назначьте роль "Администратор конфигурации RISC" (roles/riscconfigs.admin) сервисному аккаунту, который выполняет вызовы к вашему проекту. Для этого следуйте этим инструкциям.
403 API для управления потоками должны вызываться только сервисным аккаунтом. Подробнее о том, как вызывать API Google с помощью сервисного аккаунта…
403 Конечная точка доставки не принадлежит ни к одному из доменов вашего проекта. У каждого проекта есть набор авторизованных доменов. Если ваша конечная точка доставки (т.е. конечная точка, в которую должны доставляться события RISC) не размещена на одном из них, вам необходимо добавить домен конечной точки в этот набор.
403 Чтобы использовать этот API, в вашем проекте должен быть настроен хотя бы один клиент OAuth. RISC работает, только если вы создаете приложение, поддерживающее вход с аккаунтом Google. Для этого подключения требуется клиент OAuth. Если в вашем проекте нет клиентов OAuth, то, скорее всего, RISC вам не пригодится. Подробнее о том, как Google использует OAuth для своих API…
403

Неподдерживаемый статус.

Недействительный статус.

В настоящее время поддерживаются только статусы enabled и disabled.
404

В проекте нет конфигурации RISC.

В проекте нет конфигурации RISC, поэтому статус обновить нельзя.

Чтобы создать новую конфигурацию потока, вызовите конечную точку https://risc.googleapis.com/v1beta/stream:update.
4XX/5XX Невозможно сохранить статус. Чтобы узнать больше, изучите сообщение об этой ошибке.

Области действия токенов доступа

Если вы решите использовать токены доступа для аутентификации в RISC API, ваше приложение должно запрашивать следующие области действия:

Конечная точка Область действия
https://risc.googleapis.com/v1beta/stream/status https://www.googleapis.com/auth/risc.status.readonly ИЛИ https://www.googleapis.com/auth/risc.status.readwrite
https://risc.googleapis.com/v1beta/stream/status:update https://www.googleapis.com/auth/risc.status.readwrite
https://risc.googleapis.com/v1beta/stream https://www.googleapis.com/auth/risc.configuration.readonly ИЛИ https://www.googleapis.com/auth/risc.configuration.readwrite
https://risc.googleapis.com/v1beta/stream:update https://www.googleapis.com/auth/risc.configuration.readwrite
https://risc.googleapis.com/v1beta/stream:verify https://www.googleapis.com/auth/risc.verify

Нужна помощь?

Сначала ознакомьтесь с кодами ошибок. Если у вас остались вопросы, задайте их на Stack Overflow с тегом #SecEvents.