교차 계정 보호로 사용자 계정 보호

앱에서 사용자가 Google을 사용하여 자신의 계정에 로그인할 수 있는 경우 교차 계정 보호 서비스에서 제공하는 보안 이벤트 알림을 수신하고 응답하여 이러한 공유 사용자 계정의 보안을 향상할 수 있습니다.

이러한 알림은 사용자의 Google 계정에 대한 주요 변경사항에 대해 알려줍니다. 이는 종종 사용자의 앱 계정에 보안에 영향을 줄 수도 있습니다. 예를 들어 사용자의 Google 계정이 도용된 경우 이메일 계정 복구 또는 싱글 사인온(SSO) 사용을 통해 앱에서 사용자 계정이 손상될 수 있습니다.

이러한 이벤트의 위험 가능성을 완화하는 데 도움이 되도록 Google은 보안 이벤트 토큰이라는 서비스 개체를 보냅니다. 이러한 토큰은 보안 이벤트의 유형과 발생 시간, 영향을 받는 사용자의 식별자와 같은 정보를 거의 노출하지 않지만 적절한 조치를 취하는 데 사용할 수 있습니다. 예를 들어 사용자의 Google 계정이 도용된 경우 해당 사용자의 Google로 로그인을 일시적으로 비활성화하고 계정 복구 이메일이 사용자의 Gmail 주소로 전송되지 않도록 할 수 있습니다.

교차 계정 보호는 OpenID 재단에서 개발한 RISC 표준 을 기반으로 합니다.

개요

앱 또는 서비스에서 교차 계정 보호를 사용하려면 다음 작업을 완료해야 합니다.

  1. API Console에서 프로젝트를 설정하십시오.

  2. Google에서 보안 이벤트 토큰을 보낼 이벤트 수신기 엔드포인트를 만듭니다. 이 엔드포인트는 수신한 토큰의 유효성을 검사한 다음 선택한 방식으로 보안 이벤트에 응답합니다.

  3. 보안 이벤트 토큰 수신을 시작하려면 Google에 엔드포인트를 등록하세요.

전제 조건

프로필 정보 또는 이메일 주소에 대한 액세스 권한을 서비스에 부여한 Google 사용자에 대해서만 보안 이벤트 토큰을 받습니다. profile 또는 email 범위를 요청하여 이 권한을 얻습니다. 최신 Google 로 로그인 또는 기존 Google 로그인 SDK는 기본적으로 이러한 범위를 요청하지만 기본 설정을 사용하지 않거나 Google의 OpenID Connect 엔드포인트 에 직접 액세스하는 경우 다음 중 하나 이상을 요청해야 합니다. 범위.

API Console에서 프로젝트 설정

보안 이벤트 토큰 수신을 시작하려면 먼저 서비스 계정을 만들고API Console 프로젝트에서 RISC API를 활성화해야 합니다. 앱에서 Google 로그인과 같은 Google 서비스에 액세스하는 데 사용하는 것과 동일한API Console 프로젝트를 사용해야 합니다.

서비스 계정을 만들려면:

  1. API ConsoleCredentials page를 엽니다. 메시지가 표시되면 앱에서 Google 서비스에 액세스하는 데 사용하는API Console프로젝트를 선택합니다.

  2. 자격 증명 만들기 > 서비스 계정을 클릭합니다.

  3. 편집자 역할이 있는 새 서비스 계정을 만듭니다.

  4. 새로 생성된 서비스 계정에 대한 키를 생성합니다. JSON 키 유형을 선택한 다음 만들기 를 클릭합니다. 키가 생성되면 서비스 계정 자격 증명이 포함된 JSON 파일을 다운로드합니다. 이 파일을 안전한 곳에 보관하되 이벤트 수신기 끝점에서도 액세스할 수 있습니다.

프로젝트의 자격 증명 페이지에 있는 동안 Google로 로그인 또는 Google 로그인(기존)에 사용하는 클라이언트 ID도 기록해 둡니다. 일반적으로 지원하는 각 플랫폼에 대한 클라이언트 ID가 있습니다. 다음 섹션에 설명된 대로 보안 이벤트 토큰의 유효성을 검사하려면 이러한 클라이언트 ID가 필요합니다.

RISC API를 활성화하려면:

  1. API Console에서 RISC API 페이지 를 엽니다. Google 서비스에 액세스하는 데 사용하는 프로젝트가 여전히 선택되어 있는지 확인하세요.

  2. RISC 약관 을 읽고 요구 사항을 이해했는지 확인하십시오.

    조직이 소유한 프로젝트에 대해 API를 활성화하는 경우 조직을 RISC 약관에 구속할 권한이 있는지 확인하십시오.

  3. RISC 약관에 동의하는 경우에만 활성화 를 클릭합니다.

이벤트 수신기 끝점 만들기

Google에서 보안 이벤트 알림을 수신하려면 HTTPS POST 요청을 처리하는 HTTPS 엔드포인트를 생성합니다. 이 엔드포인트를 등록한 후(아래 참조) Google은 보안 이벤트 토큰이라는 암호로 서명된 문자열을 엔드포인트에 게시하기 시작합니다. 보안 이벤트 토큰은 단일 보안 관련 이벤트에 대한 정보를 포함하는 서명된 JWT입니다.

엔드포인트에서 수신하는 각 보안 이벤트 토큰에 대해 먼저 토큰의 유효성을 검사하고 디코딩한 다음 서비스에 적절하게 보안 이벤트를 처리합니다. 악의적인 행위자의 악의적인 공격을 방지하기 위해 디코딩하기 전에 이벤트 토큰의 유효성을 검사하는 것이 필수적 입니다. 다음 섹션에서는 이러한 작업에 대해 설명합니다.

1. 보안 이벤트 토큰 디코딩 및 유효성 검사

보안 이벤트 토큰은 특정 종류의 JWT이므로 jwt.io 에 나열된 것과 같은 JWT 라이브러리를 사용하여 디코딩하고 유효성을 검사할 수 있습니다. 어떤 라이브러리를 사용하든 토큰 유효성 검사 코드는 다음을 수행해야 합니다.

  1. https://accounts.google.com/.well-known/risc-configuration 에서 찾을 수 있는 Google의 RISC 구성 문서에서 교차 계정 보호 발급자 식별자( issuer ) 및 서명 키 인증서 URI( jwks_uri )를 가져옵니다.
  2. 선택한 JWT 라이브러리를 사용하여 보안 이벤트 토큰의 헤더에서 서명 키 ID를 가져옵니다.
  3. Google의 서명 키 인증서 문서에서 이전 단계에서 얻은 키 ID로 공개 키를 가져옵니다. 문서에 찾고 있는 ID의 키가 없으면 보안 이벤트 토큰이 유효하지 않을 수 있으며 엔드포인트에서 HTTP 오류 400을 반환해야 합니다.
  4. 선택한 JWT 라이브러리를 사용하여 다음을 확인합니다.
    • 보안 이벤트 토큰은 이전 단계에서 얻은 공개 키를 사용하여 서명됩니다.
    • 토큰의 aud 클레임은 앱의 클라이언트 ID 중 하나입니다.
    • 토큰의 iss 클레임은 RISC 검색 문서에서 얻은 발급자 식별자와 일치합니다. 보안 이벤트 토큰은 기록 이벤트를 나타내므로 만료되지 않으므로 토큰 만료( exp )를 확인할 필요가 없습니다.

예를 들어:

자바

java-jwtjwks-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;
}

파이썬

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"
    }
  }
}

issaud 클레임은 토큰 발행자(Google)와 토큰의 의도된 수신자(귀하의 서비스)를 나타냅니다. 이전 단계에서 이러한 소유권 주장을 확인했습니다.

jti 클레임은 단일 보안 이벤트를 식별하는 문자열이며 스트림에 고유합니다. 이 식별자를 사용하여 수신한 보안 이벤트를 추적할 수 있습니다.

events 클레임에는 토큰이 나타내는 보안 이벤트에 대한 정보가 포함되어 있습니다. 이 클레임은 이벤트 유형 식별자에서 이 이벤트와 관련된 사용자를 지정하는 subject 클레임 및 사용 가능한 이벤트에 대한 추가 세부 정보로의 매핑입니다.

subject 클레임은 사용자의 고유한 Google 계정 ID( sub )로 특정 사용자를 식별합니다. 이 Google 계정 ID는 최신 Google로 로그인( Javascript , HTML ) 라이브러리, 기존 Google 로그인 라이브러리 또는 OpenID Connect 에서 발급한 JWT ID 토큰에 포함된 동일한 식별자( sub )입니다. 클레임의 subject_typeid_token_claims 인 경우 사용자의 이메일 주소가 포함된 email 필드도 포함될 수 있습니다.

events 클레임의 정보를 사용하여 지정된 사용자 계정의 이벤트 유형에 적절한 조치를 취하십시오.

지원되는 이벤트 유형

교차 계정 보호는 다음 유형의 보안 이벤트를 지원합니다.

이벤트 유형 속성 대응 방법
https://schemas.openid.net/secevent/risc/event-type/sessions-revoked 필수 : 현재 열려 있는 세션을 종료하여 사용자 계정을 다시 보호합니다.
https://schemas.openid.net/secevent/oauth/event-type/tokens-revoked

필수 : 토큰이 Google 로그인용인 경우 현재 열려 있는 세션을 종료합니다. 또한 사용자에게 대체 로그인 방법을 설정하도록 제안할 수 있습니다.

제안 : 토큰이 다른 Google API에 액세스하기 위한 것이라면 저장한 사용자의 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-purged 제안 : 사용자의 계정을 삭제하거나 다른 로그인 방법을 제공하세요.
https://schemas.openid.net/secevent/risc/event-type/account-credential-change-required 제안 : 서비스에서 의심스러운 활동을 확인하고 적절한 조치를 취하십시오.
https://schemas.openid.net/secevent/risc/event-type/verification 상태 = state 제안 : 테스트 토큰이 수신되었음을 기록합니다.

중복 및 누락된 이벤트

교차 계정 보호는 전달되지 않은 것으로 판단되는 이벤트를 다시 전달하려고 시도합니다. 따라서 동일한 이벤트를 여러 번 수신하는 경우가 있습니다. 이로 인해 사용자에게 불편을 주는 반복 작업이 발생할 수 있는 경우 jti 클레임(이벤트의 고유 식별자)을 사용하여 이벤트 중복 제거를 고려하십시오. 중복 제거 데이터 흐름을 실행하는 데 도움이 될 수 있는 Google Cloud Dataflow 와 같은 외부 도구가 있습니다.

이벤트는 제한된 재시도와 함께 전달되므로 수신기가 장기간 다운되면 일부 이벤트를 영구적으로 놓칠 수 있습니다.

수신기 등록

보안 이벤트 수신을 시작하려면 RISC API를 사용하여 수신자 엔드포인트를 등록하십시오. RISC API 호출에는 인증 토큰이 수반되어야 합니다.

앱 사용자에 대한 보안 이벤트만 수신하므로 아래 설명된 단계의 전제 조건으로 GCP 프로젝트에 OAuth 동의 화면을 구성 해야 합니다.

1. 인증 토큰 생성

RISC API에 대한 인증 토큰을 생성하려면 다음 클레임으로 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
}

서비스 계정 키를 생성할 때 다운로드한 JSON 파일에서 찾을 수 있는 서비스 계정의 비공개 키를 사용하여 JWT에 서명합니다.

예를 들어:

자바

java-jwtGoogle의 인증 라이브러리 사용:

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

파이썬

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')

이 인증 토큰을 사용하여 1시간 동안 RISC API를 호출할 수 있습니다. 토큰이 만료되면 새 토큰을 생성하여 RISC API 호출을 계속하십시오.

2. RISC 스트림 구성 API 호출

이제 인증 토큰이 있으므로 RISC API를 사용하여 수신기 끝점 등록을 포함하여 프로젝트의 보안 이벤트 스트림을 구성할 수 있습니다.

이렇게 하려면 https://risc.googleapis.com/v1beta/stream:update 에 대한 HTTPS POST 요청을 수행하고 수신기 끝점과 관심 있는 보안 이벤트 유형을 지정합니다.

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
  ]
}

예를 들어:

자바

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

파이썬

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을 반환하면 이벤트 스트림이 성공적으로 구성되었으며 수신자 엔드포인트가 보안 이벤트 토큰 수신을 시작해야 합니다. 다음 섹션에서는 스트림 구성과 엔드포인트를 테스트하여 모든 것이 올바르게 작동하는지 확인하는 방법을 설명합니다.

현재 스트림 구성 가져오기 및 업데이트

나중에 스트림 구성을 수정하려는 경우 https://risc.googleapis.com/v1beta/stream 에 승인된 GET 요청을 수행하여 현재 스트림 구성을 가져오고 응답 본문을 수정하면 됩니다. , 그런 다음 위에서 설명한 대로 수정된 구성을 다시 https://risc.googleapis.com/v1beta/stream:update 에 게시합니다.

이벤트 스트림 중지 및 재개

Google에서 이벤트 스트림을 중지해야 하는 경우 요청 본문에 { "status": "disabled" } 를 사용하여 https://risc.googleapis.com/v1beta/stream/status:update 에 대한 승인된 POST 요청을 수행하세요. 스트림이 비활성화된 동안 Google은 이벤트를 엔드포인트로 보내지 않으며 보안 이벤트가 발생할 때 버퍼링하지 않습니다. 이벤트 스트림을 다시 활성화하려면 동일한 엔드포인트에 { "status": "enabled" } 를 POST하십시오.

3. 선택 사항: 스트림 구성 테스트

이벤트 스트림을 통해 확인 토큰을 보내 스트림 구성과 수신자 엔드포인트가 올바르게 함께 작동하는지 확인할 수 있습니다. 이 토큰은 토큰이 엔드포인트에서 수신되었는지 확인하는 데 사용할 수 있는 고유한 문자열을 포함할 수 있습니다.

인증 토큰을 요청하려면 https://risc.googleapis.com/v1beta/stream:verify 에 승인된 HTTPS POST 요청을 하십시오. 요청 본문에서 식별 문자열을 지정합니다.

{
  "state": "ANYTHING"
}

예를 들어:

자바

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

파이썬

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 전달 엔드포인트는 HTTPS URL이어야 합니다. 전달 엔드포인트(즉, RISC 이벤트가 전달될 것으로 예상하는 엔드포인트)는 HTTPS여야 합니다. RISC 이벤트를 HTTP URL로 보내지 않습니다.
403 기존 스트림 구성에는 RISC에 대한 사양 준수 전달 방법이 없습니다. GCP 프로젝트에 이미 RISC 구성이 있어야 합니다. Firebase를 사용 중이고 Google 로그인이 활성화되어 있으면 Firebase에서 프로젝트의 RISC를 관리하게 됩니다. 사용자 지정 구성을 만들 수 없습니다. Firebase 프로젝트에 Google 로그인을 사용하지 않는 경우 비활성화한 다음 1시간 후에 다시 업데이트를 시도하세요.
403 프로젝트를 찾을 수 없습니다. 올바른 프로젝트에 대해 올바른 서비스 계정을 사용하고 있는지 확인하십시오. 삭제된 프로젝트와 연결된 서비스 계정을 사용 중일 수 있습니다. 프로젝트와 연결된 모든 서비스 계정을 보는 방법을 알아보세요.
403 서비스 계정에는 프로젝트에서 편집자 권한이 있어야 합니다. 프로젝트의 Google Cloud Platform 콘솔로 이동하고 다음 안내 에 따라 호출 편집자/소유자 권한을 프로젝트에 부여하는 서비스 계정을 부여합니다.
403 스트림 관리 API는 서비스 계정에서만 호출해야 합니다. 다음 은 서비스 계정으로 Google API를 호출하는 방법 에 대한 자세한 정보입니다.
403 배달 끝점은 프로젝트 도메인에 속하지 않습니다. 모든 프로젝트에는 승인된 도메인 집합이 있습니다. 전달 엔드포인트(즉, RISC 이벤트가 전달될 것으로 예상하는 엔드포인트)가 그 중 하나에서 호스팅되지 않는 경우 해당 세트에 엔드포인트의 도메인을 추가해야 합니다.
403 이 API를 사용하려면 프로젝트에 하나 이상의 OAuth 클라이언트가 구성되어 있어야 합니다. RISC는 Google 로그인 을 지원하는 앱을 빌드하는 경우에만 작동합니다. 이 연결에는 OAuth 클라이언트가 필요합니다. 프로젝트에 OAuth 클라이언트가 없으면 RISC가 유용하지 않을 수 있습니다. Google의 API용 OAuth 사용에 대해 자세히 알아보세요.
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

도움이 필요하다?

먼저 오류 코드 참조 섹션을 확인하십시오. 여전히 질문이 있는 경우 #SecEvents 태그를 사용하여 Stack Overflow에 게시하세요.