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

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

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

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

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

نظرة عامة

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

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

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

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

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

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

إعداد مشروع في "وحدة تحكّم واجهة برمجة التطبيقات"

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

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

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

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

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

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

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

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

  1. افتح صفحة RISC API في وحدة تحكّم واجهة برمجة التطبيقات. تأكَّد من أنّ المشروع الذي تستخدمه للوصول إلى خدمات 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-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 token
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 API مصحوبة برمز تفويض مميّز.

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

1. إنشاء رمز تفويض مميّز

يمكنك إنشاء رمز تفويض لواجهة RISC API إما باستخدام Google Cloud CLI (gcloud) مع انتحال هوية حساب الخدمة (يُنصح بذلك عند فرض iam.disableServiceAccountKeyCreation أو لإعداد واجهة سطر الأوامر لمرة واحدة)، أو من خلال توقيع رمز JWT محليًا باستخدام مفتاح خاص لحساب الخدمة.

الخيار "أ": إنشاء رمز مميّز للوصول قصير الأجل باستخدام gcloud (لا حاجة إلى مفتاح JSON)

إذا كان حساب المستخدم الخاص بك يتضمّن دور "صانع الرمز المميّز لحساب الخدمة" (roles/iam.serviceAccountTokenCreator) في حساب الخدمة، يمكنك سكّ رمز دخول قصير الأجل عبر بروتوكول OAuth 2.0 مع نطاق ضبط RISC المطلوب مباشرةً من وحدة التحكّم:

AUTH_TOKEN=$(gcloud auth print-access-token \
  --impersonate-service-account=SERVICE_ACCOUNT_EMAIL \
  --scopes=https://www.googleapis.com/auth/risc.configuration.readwrite,https://www.googleapis.com/auth/risc.verify,https://www.googleapis.com/auth/risc.status.readwrite)

يمكنك الاطّلاع على نطاقات رموز الدخول لمزيد من التفاصيل حول نطاقات OAuth 2.0 المتاحة لواجهة RISC API.

الخيار (ب): إنشاء رمز JWT موقَّع ذاتيًا باستخدام مفتاح حساب خدمة

بدلاً من ذلك، لإنشاء رمز تفويض محليًا بدون رحلة ذهاب وعودة عبر الشبكة، يمكنك إنشاء رمز 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-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
  ]
}

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

جافا

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 باستخدام POST كما هو موضّح أعلاه.

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

إذا أردت إيقاف بث الأحداث من 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 عند تسجيل جهاز الاستقبال.

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

{
  "state": "ANYTHING"
}

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

جافا

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

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

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

// ...

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

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

Endpoint المستوى
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.