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

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

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

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

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

نظرة عامة

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

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

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

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

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

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

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

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

لإنشاء حساب الخدمة:

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

  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 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 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=state مقترَح: تسجيل تلقّي رمز مميّز تجريبي

الأحداث الفائتة والمكررة

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

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

تسجيل جهاز الاستقبال

لبدء تلقّي الأحداث الأمنية، سجِّل نقطة نهاية المستلِم باستخدام RISC API. يجب أن تكون الطلبات الواردة إلى RISC API مصحوبةً برمز مميز للتفويض.

ستتلقّى أحداث الأمان لمستخدمي تطبيقك فقط، لذا يجب ضبط شاشة موافقة 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 لضبط مصدر أحداث الأمان لمشروعك، بما في ذلك تسجيل نقطة النهاية للمستلِم.

لإجراء ذلك، عليك تقديم طلب HTTPS POST إلى https://risc.googleapis.com/v1beta/stream:update، مع تحديد نقطة نهاية المستلِم وأنواع أحداث الأمان التي تهمّك:

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

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

على سبيل المثال:

لغة Java

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

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

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

// ...

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

لغة Python

import requests

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

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

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

الحصول على إعدادات البث الحالية وتعديلها

إذا أردت تعديل إعدادات البث في المستقبل، يمكنك إجراء ذلك من خلال تقديم طلب GET مفوّض إلى https://risc.googleapis.com/v1beta/stream للحصول على إعدادات البث الحالية وتعديل نص الاستجابة، ثم نشر الإعدادات المعدّلة مرة أخرى على https://risc.googleapis.com/v1beta/stream:update كما هو موضّح أعلاه.

إيقاف بث الحدث واستئنافه

إذا أردت إيقاف بث الحدث من Google، يمكنك إرسال طلب POST مفوّض إلى https://risc.googleapis.com/v1beta/stream/status:update باستخدام القيمة { "status": "disabled" } في نص الطلب. عندما يتم إيقاف البث، لا ترسل Google الأحداث إلى نقطة النهاية ولا تخزِّن أحداث أمان مؤقتًا عند وقوعها. لإعادة تفعيل تدفق الأحداث، يجب نشر POST { "status": "enabled" } إلى نقطة النهاية نفسها.

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

يمكنك التحقّق من عمل إعدادات البث ونقطة نهاية المستلِم معًا بشكل صحيح من خلال إرسال رمز مميّز لإثبات الملكية من خلال بث الحدث. يمكن أن يحتوي هذا الرمز المميّز على سلسلة فريدة يمكنك استخدامها للتحقّق من استلام الرمز المميّز عند نقطة النهاية. لاستخدام هذه العملية، احرص على الاشتراك في https://schemas.openid.net/secevent/risc/event-type/verification نوع الحدث عند تسجيل المستلِم.

لطلب رمز مميز لإثبات الملكية، عليك تقديم طلب HTTPS POST معتمد إلى https://risc.googleapis.com/v1beta/stream:verify. تحديد نص سلسلة تحديده في نص الطلب:

{
  "state": "ANYTHING"
}

على سبيل المثال:

لغة Java

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

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

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

// ...

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

لغة Python

import requests
import time

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

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

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

مرجع رمز الخطأ

يمكن عرض الأخطاء التالية بواسطة RISC API:

رمز الخطأ رسالة الخطأ الإجراءات المقترَحة
400 ويجب أن يحتوي إعداد البث على حقل $fieldname. طلبك إلى نقطة النهاية https://risc.googleapis.com/v1beta/stream:update غير صالح أو يتعذّر تحليله. يُرجى تضمين $fieldname في طلبك.
401 طلب غير مسموح به. تعذّر التفويض. تأكّد من إرفاق رمز مميّز للتفويض مع الطلب ومن أنّ الرمز المميّز صالح ولم تنتهِ صلاحيته.
403 يجب أن تكون نقطة نهاية التسليم عنوان URL يستخدم HTTPS. يجب أن تكون نقطة نهاية التسليم (أي نقطة النهاية التي تتوقّع أن يتم تسليم أحداث RISC إليها) هي HTTPS. لا نرسل أحداث RISC إلى عناوين URL تستخدم HTTP.
403 إنّ إعدادات البث الحالية لا تتوافق مع مواصفات عرض RISC المتوافقة مع المواصفات. يجب أن يتضمّن مشروعك على Google Cloud إعدادات RISC حاليًا. إذا كنت تستخدم Firebase مع تفعيل ميزة "تسجيل الدخول بحساب Google"، سيكون Firebase يدير RISC لمشروعك، ولن تتمكن من إنشاء إعدادات مخصّصة. وفي حال عدم استخدام ميزة "تسجيل الدخول بحساب Google" لمشروعك على Firebase، يُرجى إيقافها ثم محاولة تعديلها مرة أخرى بعد ساعة.
403 تعذّر العثور على المشروع. تأكّد من استخدام حساب الخدمة الصحيح للمشروع الصحيح. من المحتمل أنّك تستخدم حساب خدمة مرتبطًا بمشروع محذوف. تعرَّف على كيفية الاطّلاع على جميع حسابات الخدمة المرتبطة بمشروع.
403 يحتاج حساب الخدمة إلى إذن للوصول إلى إعدادات RISC انتقِل إلى API Console مشروعك وخصِّص دور "مشرف ضبط RISC" (roles/riscconfigs.admin) إلى حساب الخدمة الذي يُجري الاستدعاءات لمشروعك عن طريق اتّباع هذه التعليمات.
403 يجب طلب واجهات برمجة التطبيقات لإدارة البث من خلال حساب خدمة فقط. إليك المزيد من المعلومات حول كيفية طلب بيانات من 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.