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

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

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

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

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

نظرة عامة

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

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

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

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

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

لن تتلقّى إلا الرموز المميّزة للأحداث الأمنية لمستخدمي Google الذين منحوا إذن الخدمة الخاص بك للوصول إلى معلومات الملف الشخصي أو عناوين البريد الإلكتروني الخاصة بهم. يمكنك الحصول على هذا الإذن من خلال طلب النطاقَين profile أو email. تطلب الإصدارات الأحدث من حزمة تسجيل الدخول باستخدام حساب Google أو حِزم تسجيل الدخول بحساب Google القديمة هذه النطاقات تلقائيًا، ولكن في حال عدم استخدام الإعدادات التلقائية أو الوصول مباشرةً إلى نقطة نهاية OpenID Connect من 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 API:

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

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

    في حال تفعيل واجهة برمجة التطبيقات لمشروع تملكه مؤسسة، تأكَّد من أنّه يُسمح لك بإلزام مؤسستك ببنود RISC.

  3. انقر على تفعيل فقط في حال الموافقة على بنود RISC.

إنشاء نقطة نهاية متلقّي الحدث

لتلقّي إشعارات الأحداث الأمنية من Google، عليك إنشاء نقطة نهاية HTTPS تتعامل مع طلبات POST لبروتوكول HTTPS. بعد تسجيل نقطة النهاية هذه (انظر أدناه)، ستبدأ 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 Discovery. تجدر الإشارة إلى أنّك لا تحتاج إلى التحقّق من تاريخ انتهاء صلاحية الرمز المميّز (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 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 APIs الأخرى، يمكنك حذف أي من رموز 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 برمز مميز للتفويض.

لن تتلقّى الأحداث الأمنية إلا لمستخدمي تطبيقك، لذا يجب ضبط شاشة طلب الموافقة المتعلّقة ببروتوكول 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 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 الأحداث إلى نقطة النهاية ولا تخزِّن الأحداث الأمنية مؤقتًا عند حدوثها. لإعادة تفعيل بث الأحداث، أدخِل { "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 ويجب أن يتم استدعاء واجهات برمجة التطبيقات لإدارة ساحة المشاركات من خلال حساب خدمة فقط. وفي ما يلي مزيد من المعلومات حول كيفية طلب البيانات من Google APIs باستخدام حساب خدمة.
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 باستخدام العلامة #Secevents.