حماية حسابات المستخدمين باستخدام ميزة "الحماية العابرة للحساب"

إذا كان تطبيقك يتيح للمستخدمين تسجيل الدخول إلى حساباتهم باستخدام Google، يمكنك تعزيز أمان حسابات هؤلاء المستخدمين المشترَكة من خلال الاستماع إلى إشعارات أحداث الأمان التي تقدّمها خدمة "الحماية العابرة للحساب" والاستجابة لها.

تنبّهك هذه الإشعارات إلى التغييرات الرئيسية التي تطرأ على حسابات Google الخاصة بالمستخدمين، والتي يمكن أن يكون لها في كثير من الأحيان آثار أمنية على حساباتهم في تطبيقك. على سبيل المثال، إذا تم الاستيلاء على حساب أحد المستخدمين على Google، قد يؤدي ذلك إلى اختراق حسابه في تطبيقك من خلال استرداد حساب البريد الإلكتروني أو استخدام ميزة "تسجيل الدخول مرّة واحدة".

لمساعدتك في الحدّ من المخاطر المحتملة لهذه الأحداث، ترسل Google عناصر الخدمة التي تُعرف باسم رموز الأحداث الأمنية. لا تعرض هذه الرموز المميزة سوى معلومات قليلة جدًا، مثل نوع حدث الأمان وتاريخ وقوعه ومعرّف المستخدم المتأثر، ولكن يمكنك استخدامها لاتّخاذ الإجراء المناسب استجابةً لذلك. على سبيل المثال، إذا تم اختراق حساب مستخدم على Google، يمكنك إيقاف ميزة "تسجيل الدخول باستخدام حساب Google" مؤقتًا لهذا المستخدم ومنع إرسال رسائل إلكترونية خاصة باسترداد الحساب إلى عنوان Gmail الخاص بالمستخدم.

تستند ميزة "الحماية العابرة للحساب" إلى معيار RISC الذي تم تطويره في مؤسسة OpenID.

نظرة عامة

لاستخدام ميزة "حماية عابرة للحساب" مع تطبيقك أو خدمتك، عليك إكمال المهام التالية:

  1. إعداد مشروعك في API Console

  2. أنشئ نقطة نهاية لتلقّي الأحداث، سترسل إليها Google رموزًا مميّزة خاصة بالأحداث الأمنية. يكون نقطة النهاية هذه مسؤولة عن التحقّق من صحة الرموز المميزة التي تتلقّاها، ثم الاستجابة لأحداث الأمان بالطريقة التي تختارها.

  3. سجِّل نقطة النهاية لدى Google لبدء تلقّي رموز مميّزة لأحداث الأمان.

المتطلبات الأساسية

لا تتلقّى رموزًا مميّزة لأحداث الأمان إلا لمستخدمي Google الذين منحوا خدمتك الإذن بالوصول إلى معلومات ملفاتهم الشخصية أو عناوين بريدهم الإلكتروني. يمكنك الحصول على هذا الإذن من خلال طلب النطاقين profile أو email. تطلب حِزم تطوير البرامج (SDK) الأحدث من Sign In With Google أو حِزم تطوير البرامج (SDK) القديمة من Google Sign-in هذه النطاقات تلقائيًا، ولكن إذا لم تستخدم الإعدادات التلقائية، أو إذا وصلت إلى نقطة نهاية OpenID Connect من Google مباشرةً، احرص على طلب نطاق واحد على الأقل من هذه النطاقات.

إعداد مشروع في API Console

قبل أن تتمكّن من بدء تلقّي رموز الأمان المميزة للأحداث، عليك إنشاء حساب خدمة وتفعيل واجهة RISC API فيAPI Console مشروعك. يجب استخدام API Console المشروع نفسه الذي تستخدمه للوصول إلى خدمات Google، مثل "تسجيل الدخول باستخدام Google"، في تطبيقك.

لإنشاء حساب الخدمة، اتّبِع الخطوات التالية:

  1. افتح API Console Credentials page. عندما يُطلب منك ذلك، اختَر API Console المشروع الذي تستخدمه للوصول إلى خدمات Google في تطبيقك.

  2. انقر على إنشاء بيانات اعتماد > حساب خدمة.

  3. أنشئ حساب خدمة جديدًا يتضمّن دور "مشرف إعدادات RISC" (roles/riscconfigs.admin) باتّباع هذه التعليمات.

  4. أنشِئ مفتاحًا لحساب الخدمة الذي أنشأته حديثًا. اختَر نوع مفتاح JSON، ثم انقر على إنشاء. عند إنشاء المفتاح، سيتم تنزيل ملف JSON يحتوي على بيانات اعتماد حساب الخدمة. احتفظ بهذا الملف في مكان آمن، ولكن يمكن الوصول إليه أيضًا من نقطة نهاية مستلِم الأحداث.

أثناء تواجدك في صفحة "بيانات الاعتماد" الخاصة بمشروعك، احرص أيضًا على تدوين أرقام تعريف العملاء التي تستخدمها في ميزة "تسجيل الدخول باستخدام حساب Google" أو ميزة "تسجيل الدخول إلى Google" (الإصدار القديم). عادةً، يكون لديك معرّف عميل لكل منصة تتوافق معها. ستحتاج إلى معرّفات العملاء هذه للتحقّق من صحة رموز الأمان المميزة، كما هو موضّح في القسم التالي.

لتفعيل واجهة RISC API، اتّبِع الخطوات التالية:

  1. افتح صفحة RISC API فيAPI Console. تأكَّد من أنّ المشروع الذي تستخدمه للوصول إلى خدمات Google لا يزال محدّدًا.

  2. اقرأ بنود RISC وتأكَّد من فهم المتطلبات.

    إذا كنت بصدد تفعيل واجهة برمجة التطبيقات لمشروع تملكه مؤسسة، تأكَّد من أنّ لديك الإذن بربط مؤسستك ببنود 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، احصل على المفتاح العام الذي يتضمّن معرّف المفتاح الذي حصلت عليه في الخطوة السابقة. إذا لم تتضمّن المستند مفتاحًا يتضمّن المعرّف الذي تبحث عنه، من المحتمل أن يكون رمز الأمان المميّز للحدث غير صالح، ويجب أن تعرض نقطة النهاية الخطأ 400 في HTTP.
  4. باستخدام مكتبة JWT التي تختارها، تحقَّق مما يلي:
    • يتم توقيع الرمز المميز لحدث الأمان باستخدام المفتاح العام الذي حصلت عليه في الخطوة السابقة.
    • تمثّل المطالبة aud في الرمز المميز أحد معرّفات العملاء لتطبيقاتك.
    • تتطابق مطالبة iss للرمز المميّز مع معرّف جهة الإصدار الذي حصلت عليه من مستند اكتشاف 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، تحدّد المستخدم الذي يتعلّق به هذا الحدث، وإلى أي تفاصيل إضافية حول الحدث قد تكون متاحة.

يحدّد الادعاء subject مستخدمًا معيّنًا من خلال معرّف حساب Google الفريد الخاص بالمستخدم (sub). معرّف حساب Google هذا هو المعرّف نفسه (sub) الوارد في رموز JWT المميزة التي تصدرها المكتبة الأحدث من "تسجيل الدخول باستخدام حساب Google" (JavaScript وHTML) أو المكتبة القديمة من تسجيل الدخول باستخدام حساب Google أو OpenID Connect. عندما تكون قيمة subject_type للمطالبة هي id_token_claims، قد تتضمّن أيضًا حقل email يحتوي على عنوان البريد الإلكتروني للمستخدم.

استخدِم المعلومات الواردة في مطالبة events لاتّخاذ الإجراء المناسب لنوع الحدث في حساب المستخدم المحدّد.

معرّفات رموز OAuth المميزة

بالنسبة إلى أحداث OAuth المتعلقة برموز مميزة فردية، يحتوي نوع المعرّف موضوع الرمز المميز على الحقول التالية:

  • 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"، عليك إنهاء الجلسات المفتوحة حاليًا. بالإضافة إلى ذلك، يمكنك أن تقترح على المستخدم إعداد طريقة تسجيل دخول بديلة.

اقتراح: إذا كان الرمز المميّز مخصّصًا للوصول إلى واجهات برمجة تطبيقات أخرى من 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 مصحوبة برمز مميز للموافقة.

لن تتلقّى أحداثًا أمنية إلا لمستخدمي تطبيقك، لذا عليك ضبط شاشة موافقة OAuth في مشروعك على Google Cloud Platform كشرط أساسي للخطوات الموضّحة أدناه.

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
}

وقِّع رمز 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.

2. استدعاء واجهة برمجة التطبيقات الخاصة بإعدادات بث 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 الأخطاء التالية:

رمز الخطأ رسالة خطأ الإجراءات المقترَحة
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 وتم تفعيل ميزة &quot;تسجيل الدخول باستخدام Google&quot;، ستتولّى Firebase إدارة RISC لمشروعك، ولن تتمكّن من إنشاء إعدادات مخصّصة. إذا كنت لا تستخدم ميزة "تسجيل الدخول بحساب Google" لمشروعك على Firebase، يُرجى إيقافها، ثم محاولة التعديل مرة أخرى بعد ساعة.
403 تعذّر العثور على المشروع. تأكَّد من استخدام حساب الخدمة الصحيح للمشروع الصحيح. قد تستخدم حساب خدمة مرتبطًا بمشروع تم حذفه. كيفية الاطّلاع على جميع حسابات الخدمة المرتبطة بمشروع
403 يجب أن يمتلك حساب الخدمة إذنًا بالوصول إلى إعدادات RISC انتقِل إلى مشروعك API Console وأسند دور "مشرف إعدادات RISC" (roles/riscconfigs.admin) إلى حساب الخدمة الذي يجري طلبات إلى مشروعك باتّباع هذه التعليمات.
403 يجب أن يتم استدعاء واجهات برمجة التطبيقات لإدارة البث من خلال حساب خدمة فقط. يمكنك الاطّلاع على مزيد من المعلومات حول كيفية استدعاء واجهات Google API باستخدام حساب خدمة.
403 لا تنتمي نقطة التسليم إلى أي من نطاقات مشروعك. يتضمّن كل مشروع مجموعة من النطاقات المسموح بها. إذا لم تكن نقطة نهاية التسليم (أي نقطة النهاية التي تتوقّع أن يتم تسليم أحداث RISC إليها) مستضافة على إحدى هذه النطاقات، عليك إضافة نطاق نقطة النهاية إلى هذه المجموعة.
403 لاستخدام واجهة برمجة التطبيقات هذه، يجب أن يتضمّن مشروعك برنامج OAuth واحدًا على الأقل تم ضبطه. لا تعمل خدمة RISC إلا إذا أنشأت تطبيقًا يتيح استخدام تسجيل الدخول باستخدام حساب Google. يتطلّب هذا الربط عميل OAuth. إذا لم يكن مشروعك يتضمّن عملاء OAuth، من المحتمل ألا يكون RISC مفيدًا لك. مزيد من المعلومات حول استخدام Google لبروتوكول 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

هل تحتاج إلى مساعدة؟

في البداية، اطّلِع على قسم مرجع رموز الخطأ. إذا كانت لديك أسئلة أخرى، يمكنك طرحها على Stack Overflow باستخدام العلامة #SecEvents.