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

تنظيم صفحاتك في مجموعات يمكنك حفظ المحتوى وتصنيفه حسب إعداداتك المفضّلة.

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

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

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

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

نظرة عامة

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

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

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

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

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

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

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

قبل أن تتمكّن من بدء تلقّي الرموز المميّزة لأحداث الأمان، عليك إنشاء حساب خدمة وتفعيل واجهة برمجة تطبيقات RISC في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:

  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، يمكنك الحصول على المفتاح العام مع رقم تعريف المفتاح الذي حصلت عليه في الخطوة السابقة. إذا لم يحتوي المستند على مفتاح مع المعرّف الذي تبحث عنه، من المحتمل أن الرمز المميّز للحدث الأمني غير صالح، ويجب أن تعرض نقطة النهاية خطأ HTTP 400.
  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 مستخدمًا معيّنًا لديه رقم تعريف الحساب الفريد للمستخدم على Google (sub). ويكون رقم تعريف حساب Google هذا هو المعرّف نفسه (sub) المضمّن في الرموز المميّزة لمعرّف JWT التي تم إصدارها من خلال ميزة "تسجيل الدخول باستخدام حساب Google" الجديدة (JavaScript أو HTML) أو مكتبة تسجيل الدخول بحساب Google القديمة أواتصال OpenID. عندما تكون 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 API الأخرى، عليك حذف أيّ من رموز 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-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. يجب أن تكون الطلبات الواردة إلى واجهة برمجة تطبيقات RISC مصحوبة برمز مميز للتفويض.

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

1- إنشاء رمز مميز للتفويض

لإنشاء رمز تفويض مميز لواجهة برمجة تطبيقات RISC، أنشئ 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) لمدة ساعة واحدة. عند انتهاء صلاحية الرمز المميَّز، يمكنك إنشاء رمز مميز جديد لمواصلة إجراء طلبات البيانات من واجهة برمجة التطبيقات (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 الأحداث إلى نقطة النهاية، ولا تخزِّن الأحداث الأمنية مؤقتًا عند حدوثها. لإعادة تفعيل بث الحدث، عليك نشر { "status": "enabled" } مع نقطة النهاية نفسها.

3. اختياري: اختبار إعدادات البث

يمكنك التحقّق من أنّ إعدادات البث ونقطة نهاية المستلِم تعمل معًا بشكل صحيح عن طريق إرسال رمز مميّز لإثبات ملكية النطاق من خلال بث الحدث. يمكن أن يحتوي هذا الرمز المميّز على سلسلة فريدة يمكنك استخدامها للتحقق من أنّ الرمز المميّز قد تم استلامه في نقطة النهاية.

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

نقطة النهاية النطاق
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 باستخدام العلامة #SecEvent.