تقديم طلب عادي من واجهة برمجة التطبيقات

توضّح هذه الصفحة عملية إجراء الطلبات العادية للبيانات من واجهة برمجة التطبيقات للحصول على بيانات السلامة، وهي متاحة في الإصدار 5.0 من نظام التشغيل Android (المستوى 21 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث. يمكنك إرسال طلب بيانات عادي من واجهة برمجة التطبيقات للحصول على بيان السلامة عندما يستدعي تطبيقك الخادم للتحقّق مما إذا كان التفاعل حقيقيًا أم لا.

نظرة عامة

مخطّط بياني للتسلسل يوضّح التصميم العالي المستوى لواجهة برمجة التطبيقات Play Integrity API

يتكون الطلب العادي من جزأين:

  • إعداد موفِّر الرموز المميّزة للأمان (مرة واحدة): عليك طلب واجهة برمجة التطبيقات Integrity API لإعداد موفِّر الرموز المميّزة للأمان قبل الحصول على بيان السلامة. على سبيل المثال، يمكنك إجراء ذلك عند إطلاق تطبيقك أو تشغيله في الخلفية قبل الحاجة إلى بيان السلامة.
  • طلب رمز مميَّز لسلامة تطبيقك (عند الطلب): عندما يطلب تطبيقك من أحد الخوادم التحقق من أنّ تطبيقك أصلي، عليك طلب رمز مميّز لضمان السلامة وإرساله إلى خادم الخلفية في تطبيقك لفك التشفير والتحقّق منه. ومن ثم يمكن لخادم الخلفية تحديد طريقة التصرف.

تجهيز موفّر الرموز المميّزة للأمان (إجراء واحد):

  1. يطلب تطبيقك من موفّر الرموز المميّزة السلامة من خلال رقم مشروع Google Cloud الخاص بك.
  2. يحتفظ تطبيقك بموفِّر السلامة في الذاكرة لإجراء مزيد من استدعاءات التحقق من المصادقة.

طلب رمز مميَّز للسلامة (عند الطلب):

  1. فيما يحتاج تطبيقك إلى حمايته، يحتسب تطبيقك التجزئة (باستخدام أي خوارزمية تجزئة مناسبة مثل SHA256) للطلب الذي سيتم إجراؤه.
  2. يطلب تطبيقك رمزًا مميّزًا للأمان، مع تمرير تجزئة الطلب.
  3. يتلقّى تطبيقك رمز السلامة المميّز الموقَّع والمشفَّر من واجهة برمجة التطبيقات Play Integrity API.
  4. يمرّر تطبيقك الرمز المميّز للسلامة إلى خلفية تطبيقك.
  5. ترسل الواجهة الخلفية لتطبيقك الرمز المميّز إلى خادم Google Play. يفك خادم Google Play بيان السلامة ويتحقق منه، ويعرض النتائج إلى الواجهة الخلفية للتطبيق.
  6. وتحدّد الواجهة الخلفية لتطبيقك كيفية المتابعة استنادًا إلى الإشارات المضمَّنة في حمولة البيانات الخاصة بالرمز المميّز.
  7. ترسل خلفية تطبيقك نتائج القرار إلى تطبيقك.

تجهيز موفّر الرموز المميّزة للأمان (غير متوفّر)

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

يمكنك إعداد موفّر الرموز المميّزة للأمان على النحو التالي:

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

لإعداد موفِّر خدمة الرموز المميّزة للسلامة، اتّبِع الخطوات التالية:

  1. أنشئ StandardIntegrityManager، كما هو موضّح في الأمثلة التالية.
  2. يمكنك إنشاء PrepareIntegrityTokenRequest مع توفير رقم مشروع Google Cloud من خلال طريقة setCloudProjectNumber().
  3. يمكنك استخدام المدير للاتصال بـ prepareIntegrityToken()، وتوفير PrepareIntegrityTokenRequest.

Java

import com.google.android.gms.tasks.Task;

// Create an instance of a manager.
StandardIntegrityManager standardIntegrityManager =
    IntegrityManagerFactory.createStandard(applicationContext);

StandardIntegrityTokenProvider integrityTokenProvider;
long cloudProjectNumber = ...;

// Prepare integrity token. Can be called once in a while to keep internal
// state fresh.
standardIntegrityManager.prepareIntegrityToken(
    PrepareIntegrityTokenRequest.builder()
        .setCloudProjectNumber(cloudProjectNumber)
        .build())
    .addOnSuccessListener(tokenProvider -> {
        integrityTokenProvider = tokenProvider;
    })
    .addOnFailureListener(exception -> handleError(exception));

الانسجام

IEnumerator PrepareIntegrityTokenCoroutine() {
    long cloudProjectNumber = ...;

    // Create an instance of a standard integrity manager.
    var standardIntegrityManager = new StandardIntegrityManager();

    // Request the token provider.
    var integrityTokenProviderOperation =
      standardIntegrityManager.PrepareIntegrityToken(
        new PrepareIntegrityTokenRequest(cloudProjectNumber));

    // Wait for PlayAsyncOperation to complete.
    yield return integrityTokenProviderOperation;

    // Check the resulting error code.
    if (integrityTokenProviderOperation.Error != StandardIntegrityErrorCode.NoError)
    {
        AppendStatusLog("StandardIntegrityAsyncOperation failed with error: " +
                integrityTokenProviderOperation.Error);
        yield break;
    }

    // Get the response.
    var integrityTokenProvider = integrityTokenProviderOperation.GetResult();
}

مدمجة مع المحتوى

/// Initialize StandardIntegrityManager
StandardIntegrityManager_init(/* app's java vm */, /* an android context */);
/// Create a PrepareIntegrityTokenRequest opaque object.
int64_t cloudProjectNumber = ...;
PrepareIntegrityTokenRequest* tokenProviderRequest;
PrepareIntegrityTokenRequest_create(&tokenProviderRequest);
PrepareIntegrityTokenRequest_setCloudProjectNumber(tokenProviderRequest, cloudProjectNumber);

/// Prepare a StandardIntegrityTokenProvider opaque type pointer and call
/// StandardIntegrityManager_prepareIntegrityToken().
StandardIntegrityTokenProvider* tokenProvider;
StandardIntegrityErrorCode error_code =
        StandardIntegrityManager_prepareIntegrityToken(tokenProviderRequest, &tokenProvider);

/// ...
/// Proceed to polling iff error_code == STANDARD_INTEGRITY_NO_ERROR
if (error_code != STANDARD_INTEGRITY_NO_ERROR)
{
    /// Remember to call the *_destroy() functions.
    return;
}
/// ...
/// Use polling to wait for the async operation to complete.

IntegrityResponseStatus token_provider_status;

/// Check for error codes.
StandardIntegrityErrorCode error_code =
        StandardIntegrityTokenProvider_getStatus(tokenProvider, &token_provider_status);
if (error_code == STANDARD_INTEGRITY_NO_ERROR
    && token_provider_status == INTEGRITY_RESPONSE_COMPLETED)
{
    /// continue to request token from the token provider
}
/// ...
/// Remember to free up resources.
PrepareIntegrityTokenRequest_destroy(tokenProviderRequest);

الحماية من التلاعب في الطلبات (يُنصح به)

عند التحقّق من إجراء المستخدم في تطبيقك باستخدام واجهة برمجة التطبيقات Play Integrity API، يمكنك الاستفادة من حقل requestHash للحدّ من هجمات التلاعب. على سبيل المثال، قد ترغب لعبة في إبلاغ خادم الخلفية بنتيجة اللاعب عن نتيجة اللاعب، ويريد الخادم التأكد من عدم التلاعب بهذه النتيجة من قِبل خادم وكيل. تعرض واجهة برمجة التطبيقات Play Integrity API القيمة التي حدّدتها في الحقل requestHash ضمن الردّ الموقَّع بشأن السلامة. بدون "requestHash"، سيتم ربط رمز السلامة المميّز بالجهاز فقط، وليس بالطلب المحدَّد، ما يزيد من احتمال التعرّض لهجمات. توضّح التعليمات التالية كيفية الاستفادة من الحقل requestHash بشكل فعّال:

عند طلب بيان سلامة:

  • يمكنك الحصول على ملخّص لجميع مَعلمات الطلب ذات الصلة (مثل SHA256 لتسلسل طلب ثابت) من إجراء المستخدِم أو طلب الخادم الجاري. الحد الأقصى لطول القيمة المضبوطة في الحقل requestHash هو 500 بايت. يُرجى تضمين أي بيانات خاصة بطلبات التطبيقات في "requestHash"، وهي بيانات مهمة أو ذات صلة بالإجراء الذي يتم التحقّق منه أو حمايته. يتم تضمين الحقل requestHash حرفيًا في الرمز المميّز للسلامة، لذا قد تؤدي القيم الطويلة إلى زيادة حجم الطلب.
  • قدِّم الملخّص باعتباره حقل requestHash إلى واجهة برمجة التطبيقات Play Integrity API، واحصل على الرمز المميّز الخاص بسلامة التطبيق.

عند تلقّي بيان سلامة:

  • يجب فك ترميز الرمز المميّز للأمان، واستخراج الحقل requestHash.
  • احتساب ملخص للطلب بالطريقة نفسها المستخدَمة في التطبيق (مثلاً SHA256 لتسلسل ثابت للطلبات)
  • مقارنة الملخّصات من جهة التطبيق ومن جهة الخادم وفي حال عدم التطابق، يصبح الطلب غير موثوق به.

طلب بيان السلامة (عند الطلب)

بعد إعداد موفِّر الرموز المميّزة للأمان، يمكنك بدء طلب بيانات السلامة من Google Play. للقيام بذلك، أكمل الخطوات التالية:

  1. يجب الحصول على StandardIntegrityTokenProvider، كما هو موضَّح أعلاه.
  2. يمكنك إنشاء StandardIntegrityTokenRequest، مع توفير تجزئة الطلب لإجراء المستخدم الذي تريد حمايته من خلال طريقة setRequestHash.
  3. يمكنك استخدام موفِّر الرمز المميّز للأمان لطلب request() وتوفير StandardIntegrityTokenRequest.

Java

import com.google.android.gms.tasks.Task;

StandardIntegrityTokenProvider integrityTokenProvider;

// See above how to prepare integrityTokenProvider.

// Request integrity token by providing a user action request hash. Can be called
// several times for different user actions.
String requestHash = "2cp24z...";
Task<StandardIntegrityToken> integrityTokenResponse =
    integrityTokenProvider.request(
        StandardIntegrityTokenRequest.builder()
            .setRequestHash(requestHash)
            .build());
integrityTokenResponse
    .addOnSuccessListener(response -> sendToServer(response.token()))
    .addOnFailureListener(exception -> handleError(exception));

الانسجام

IEnumerator RequestIntegrityTokenCoroutine() {
    StandardIntegrityTokenProvider integrityTokenProvider;

    // See above how to prepare integrityTokenProvider.

    // Request integrity token by providing a user action request hash. Can be called
    // several times for different user actions.
    String requestHash = "2cp24z...";
    var integrityTokenOperation = integrityTokenProvider.Request(
      new StandardIntegrityTokenRequest(requestHash)
    );

    // Wait for PlayAsyncOperation to complete.
    yield return integrityTokenOperation;

    // Check the resulting error code.
    if (integrityTokenOperation.Error != StandardIntegrityErrorCode.NoError)
    {
        AppendStatusLog("StandardIntegrityAsyncOperation failed with error: " +
                integrityTokenOperation.Error);
        yield break;
    }

    // Get the response.
    var integrityToken = integrityTokenOperation.GetResult();
}

مدمجة مع المحتوى

/// Create a StandardIntegrityTokenRequest opaque object.
const char* requestHash = ...;
StandardIntegrityTokenRequest* tokenRequest;
StandardIntegrityTokenRequest_create(&tokenRequest);
StandardIntegrityTokenRequest_setRequestHash(tokenRequest, requestHash);

/// Prepare a StandardIntegrityToken opaque type pointer and call
/// StandardIntegrityTokenProvider_request(). Can be called several times for
/// different user actions. See above how to prepare token provider.
StandardIntegrityToken* token;
StandardIntegrityErrorCode error_code =
        StandardIntegrityTokenProvider_request(tokenProvider, tokenRequest, &token);

/// ...
/// Proceed to polling iff error_code == STANDARD_INTEGRITY_NO_ERROR
if (error_code != STANDARD_INTEGRITY_NO_ERROR)
{
    /// Remember to call the *_destroy() functions.
    return;
}
/// ...
/// Use polling to wait for the async operation to complete.

IntegrityResponseStatus token_status;

/// Check for error codes.
StandardIntegrityErrorCode error_code =
        StandardIntegrityToken_getStatus(token, &token_status);
if (error_code == STANDARD_INTEGRITY_NO_ERROR
    && token_status == INTEGRITY_RESPONSE_COMPLETED)
{
    const char* integrityToken = StandardIntegrityToken_getToken(token);
}
/// ...
/// Remember to free up resources.
StandardIntegrityTokenRequest_destroy(tokenRequest);
StandardIntegrityToken_destroy(token);
StandardIntegrityTokenProvider_destroy(tokenProvider);
StandardIntegrityManager_destroy();

فك تشفير بيان السلامة والتحقّق منه

بعد طلب بيان السلامة، توفِّر واجهة برمجة التطبيقات Play Integrity API رمز استجابة مشفّرًا. للحصول على بيانات سلامة الجهاز، عليك فك تشفير رمز السلامة على خوادم Google. للقيام بذلك، أكمل هذه الخطوات:

  1. يمكنك إنشاء حساب خدمة ضمن مشروع Google Cloud المرتبط بتطبيقك.
  2. على خادم تطبيقك، عليك جلب رمز الدخول من بيانات اعتماد حساب الخدمة باستخدام نطاق Playintegrity، وتقديم الطلب التالي:

    playintegrity.googleapis.com/v1/PACKAGE_NAME:decodeIntegrityToken -d \
    '{ "integrity_token": "INTEGRITY_TOKEN" }'
  3. اقرأ استجابة JSON.

الحمولة الناتجة هي رمز مميّز بنص عادي يحتوي على بيانات السلامة.

الحماية التلقائية لإعادة التشغيل

للحدّ من هجمات إعادة التشغيل، يضمن Google Play تلقائيًا عدم إعادة استخدام كل رمز مميَّز للتحقّق من التكامل عدة مرات. وستؤدي محاولة فك تشفير الرمز نفسه بشكل متكرر إلى إصدار بيان فارغ.