دليل نقل التدفق خارج النطاق (OOB)

نظرة عامة

في 16 شباط (فبراير) 2022، أعلنّا عن خطط لجعل التفاعلات مع Google OAuth أكثر أمانًا من خلال استخدام مسارات OAuth أكثر أمانًا. يساعدك هذا الدليل في فهم التغييرات والخطوات اللازمة للانتقال بنجاح من عملية OAuth خارج النطاق (OOB) إلى البدائل المتوافقة.

هذه الجهود هي إجراء وقائي ضد هجمات التصيّد الاحتيالي وانتحال هوية التطبيقات أثناء التفاعل مع نقاط نهاية التفويض في بروتوكول OAuth 2.0 من Google.

ما هو OOB؟

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

سيتم إيقاف مسار OOB نهائيًا لجميع أنواع العملاء، أي تطبيقات الويب وتطبيقات Android وiOS وUniversal Windows Platform (UWP) وتطبيقات Chrome وأجهزة التلفزيون والأجهزة ذات الإدخال المحدود وتطبيقات الكمبيوتر.

تواريخ الامتثال الرئيسية

  • ‫28 فبراير 2022: تم حظر الاستخدام الجديد لبروتوكول OAuth في مسار OOB
  • ‫5 سبتمبر 2022: قد يتم عرض رسالة تحذير للمستخدمين بشأن طلبات OAuth غير المتوافقة
  • ‫3 أكتوبر 2022: تم إيقاف مسار OOB نهائيًا لمعرّفات عملاء OAuth التي تم إنشاؤها قبل 28 فبراير 2022
  • ‫31 يناير 2023 - سيتم حظر جميع العملاء الحاليين (بما في ذلك العملاء المعفون)

سيتم عرض رسالة خطأ للمستخدمين بشأن الطلبات غير المتوافقة. ستوضّح الرسالة للمستخدمين أنّه تم حظر التطبيق، مع عرض عنوان البريد الإلكتروني المخصّص للدعم الذي سجّلته في شاشة طلب الموافقة المتعلّقة ببروتوكول OAuth في Google API Console.

هناك خطوتان رئيسيتان لإكمال عملية نقل البيانات:
  1. تحديد ما إذا كنت متأثرًا بهذا التغيير
  2. انتقِل إلى حل بديل أكثر أمانًا إذا كنت متأثرًا.

تحديد ما إذا كنت متأثرًا

لا ينطبق هذا الإيقاف النهائي إلا على التطبيقات المتاحة للجميع (أي التطبيقات التي تم ضبط حالة النشر فيها على في مرحلة الإنتاج). سيظل مسار الموافقة يعمل للتطبيقات التي تحمل حالة النشر "قيد الاختبار".

راجِع حالة النشر في صفحة Branding page Google Cloud Console في بروتوكول OAuth، وانتقِل إلى الخطوة التالية إذا كنت تستخدم تدفق OOB في مشروع بحالة نشر "في مرحلة الإنتاج".

كيفية تحديد ما إذا كان تطبيقك يستخدم مسار OOB

افحص رمز تطبيقك أو طلب الشبكة الصادر (في حال كان تطبيقك يستخدم مكتبة OAuth) لتحديد ما إذا كان طلب التفويض الذي يرسله تطبيقك إلى Google OAuth يستخدم قيمة معرّف موارد منتظم لإعادة التوجيه خارج النطاق.

فحص رمز التطبيق

راجِع قسم رمز التطبيق الذي تجري فيه عمليات طلب إلى نقاط نهاية التفويض في Google OAuth، وحدِّد ما إذا كانت المَعلمة redirect_uri تتضمّن أيًا من القيم التالية:
  • redirect_uri=urn:ietf:wg:oauth:2.0:oob
  • redirect_uri=urn:ietf:wg:oauth:2.0:oob:auto
  • redirect_uri=oob
سيبدو طلب نموذجي لعملية إعادة التوجيه خارج النطاق على النحو التالي:
https://accounts.google.com/o/oauth2/v2/auth?
response_type=code&
scope=<SCOPES>&
state=<STATE>&
redirect_uri=urn:ietf:wg:oauth:2.0:oob&
client_id=<CLIENT_ID>

فحص مكالمة الشبكة الصادرة

تختلف طريقة فحص طلبات الشبكة حسب نوع تطبيق العميل.
أثناء فحص طلبات الشبكة، ابحث عن الطلبات المُرسَلة إلى نقاط نهاية التفويض في Google OAuth وحدِّد ما إذا كانت المَعلمة redirect_uri تتضمّن أيًا من القيم التالية:
  • redirect_uri=urn:ietf:wg:oauth:2.0:oob
  • redirect_uri=urn:ietf:wg:oauth:2.0:oob:auto
  • redirect_uri=oob
سيبدو طلب نموذجي لعملية إعادة التوجيه خارج النطاق على النحو التالي:
https://accounts.google.com/o/oauth2/v2/auth?
response_type=code&
scope=<SCOPES>&
state=<STATE>&
redirect_uri=urn:ietf:wg:oauth:2.0:oob&
client_id=<CLIENT_ID>

الانتقال إلى حل بديل آمن

برامج العملاء على الأجهزة الجوّالة (Android / iOS)

إذا تبيّن لك أنّ تطبيقك يستخدم مسار OOB مع نوع عميل OAuth على Android أو iOS، عليك نقل البيانات إلى حِزم تطوير البرامج (SDK) المقترَحة (Android وiOS).

يسهّل حزمة SDK الوصول إلى Google APIs ويتعامل مع جميع طلبات البيانات من نقاط نهاية التفويض في بروتوكول OAuth 2.0 من Google.

تقدّم روابط المستندات أدناه معلومات حول كيفية استخدام حِزم SDK المقترَحة للوصول إلى واجهات Google API بدون استخدام معرّف موارد منتظم (URI) لإعادة التوجيه خارج النطاق.

الوصول إلى واجهات Google API على Android

إذن الوصول من جهة العميل

يوضّح المثال التالي كيفية الوصول إلى Google APIs على جانب العميل على Android باستخدام مكتبة Google Identity Services Android المقترَحة.

  List requestedScopes = Arrays.asList(DriveScopes.DRIVE_APPDATA);
    AuthorizationRequest authorizationRequest = AuthorizationRequest.builder().setRequestedScopes(requestedScopes).build();
    Identity.getAuthorizationClient(activity)
            .authorize(authorizationRequest)
            .addOnSuccessListener(
                authorizationResult -> {
                  if (authorizationResult.hasResolution()) {
                    // Access needs to be granted by the user
                    PendingIntent pendingIntent = authorizationResult.getPendingIntent();
                    try {
    startIntentSenderForResult(pendingIntent.getIntentSender(),
    REQUEST_AUTHORIZE, null, 0, 0, 0, null);
                    } catch (IntentSender.SendIntentException e) {
                    Log.e(TAG, "Couldn't start Authorization UI: " + e.getLocalizedMessage());
                    }
                  } else {
                    // Access already granted, continue with user action
                    saveToDriveAppFolder(authorizationResult);
                  }
                })
            .addOnFailureListener(e -> Log.e(TAG, "Failed to authorize", e));

مرِّر authorizationResult إلى الطريقة المحدّدة لحفظ المحتوى في مجلد Drive الخاص بالمستخدم. يحتوي authorizationResult على الطريقة getAccessToken() التي تعرض رمز الدخول.

الوصول من جهة الخادم (بلا إنترنت)
يوضّح المثال التالي كيفية الوصول إلى واجهات Google API من جهة الخادم على Android.
  List requestedScopes = Arrays.asList(DriveScopes.DRIVE_APPDATA);
    AuthorizationRequest authorizationRequest = AuthorizationRequest.builder()
    .requestOfflineAccess(webClientId)
            .setRequestedScopes(requestedScopes)
            .build();
    Identity.getAuthorizationClient(activity)
            .authorize(authorizationRequest)
            .addOnSuccessListener(
                authorizationResult -> {
                  if (authorizationResult.hasResolution()) {
                    // Access needs to be granted by the user
                    PendingIntent pendingIntent = authorizationResult.getPendingIntent();
                    try {
    startIntentSenderForResult(pendingIntent.getIntentSender(),
    REQUEST_AUTHORIZE, null, 0, 0, 0, null);
                    } catch (IntentSender.SendIntentException e) {
                    Log.e(TAG, "Couldn't start Authorization UI: " + e.getLocalizedMessage());
                    }
                  } else {
                    String authCode = authorizationResult.getServerAuthCode();
                  }
                })
            .addOnFailureListener(e -> Log.e(TAG, "Failed to authorize", e));

يتضمّن authorizationResult الطريقة getServerAuthCode() التي تعرض رمز التفويض الذي يمكنك إرساله إلى الخلفية للحصول على رمز دخول ورمز مميز لإعادة التحميل.

الوصول إلى واجهات Google API في تطبيق iOS

إذن الوصول من جهة العميل

يوضّح المثال أدناه كيفية الوصول إلى Google APIs من جهة العميل على iOS.

user.authentication.do { authentication, error in
  guard error == nil else { return }
  guard let authentication = authentication else { return }
  
  // Get the access token to attach it to a REST or gRPC request.
  let accessToken = authentication.accessToken
  
  // Or, get an object that conforms to GTMFetcherAuthorizationProtocol for
  // use with GTMAppAuth and the Google APIs client library.
  let authorizer = authentication.fetcherAuthorizer()
}

استخدِم رمز الدخول لاستدعاء واجهة برمجة التطبيقات، إما عن طريق تضمين رمز الدخول في عنوان طلب REST أو gRPC (Authorization: Bearer ACCESS_TOKEN)، أو باستخدام أداة التحقّق من أذونات fetcher (GTMFetcherAuthorizationProtocol) مع مكتبة برامج Google APIs للغة Objective-C الخاصة بطلبات REST.

راجِع دليل الوصول من جهة العميل لمعرفة كيفية الوصول إلى واجهات Google APIs من جهة العميل. حول كيفية الوصول إلى واجهات Google APIs من جهة العميل.

الوصول من جهة الخادم (بلا إنترنت)
يوضّح المثال أدناه كيفية الوصول إلى واجهات Google APIs من جهة الخادم لتوفير الدعم لعميل iOS.
GIDSignIn.sharedInstance.signIn(with: signInConfig, presenting: self) { user, error in
  guard error == nil else { return }
  guard let user = user else { return }
  
  // request a one-time authorization code that your server exchanges for
  // an access token and refresh token
  let authCode = user.serverAuthCode
}

راجِع دليل الوصول من جهة الخادم للتعرّف على كيفية الوصول إلى واجهات برمجة تطبيقات Google من جهة الخادم.

عميل تطبيق Chrome

إذا تبيّن لك أنّ تطبيقك يستخدم مسار OOB على عميل تطبيق Chrome، عليك الانتقال إلى استخدام Chrome Identity API.

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

window.onload = function() {
  document.querySelector('button').addEventListener('click', function() {

  
  // retrieve access token
  chrome.identity.getAuthToken({interactive: true}, function(token) {
  
  // ..........


  // the example below shows how to use a retrieved access token with an appropriate scope
  // to call the Google People API contactGroups.get endpoint

  fetch(
    'https://people.googleapis.com/v1/contactGroups/all?maxMembers=20&key=API_KEY',
    init)
    .then((response) => response.json())
    .then(function(data) {
      console.log(data)
    });
   });
 });
};

راجِع دليل Chrome Identity API لمزيد من المعلومات حول كيفية الوصول إلى المستخدمين الذين تمّت مصادقتهم واستدعاء نقاط نهاية Google باستخدام Chrome Identity API.

تطبيق الويب

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

تسهّل المكتبات الوصول إلى واجهات برمجة التطبيقات من Google والتعامل مع جميع الطلبات الموجّهة إلى نقاط النهاية من Google.

الوصول من جهة الخادم (بلا إنترنت)
يتطلّب وضع الوصول من جهة الخادم (خارج الإنترنت) تنفيذ ما يلي:

تعرض مقتطفة الرمز البرمجي أدناه مثالاً على NodeJS لاستخدام Google Drive API لعرض قائمة بملفات Google Drive الخاصة بالمستخدم على جهة الخادم بدون استخدام معرّف موارد منتظم لإعادة التوجيه خارج النطاق.

async function main() {
  const server = http.createServer(async function (req, res) {

  if (req.url.startsWith('/oauth2callback')) {
    let q = url.parse(req.url, true).query;

    if (q.error) {
      console.log('Error:' + q.error);
    } else {
      
      // Get access and refresh tokens (if access_type is offline)
      let { tokens } = await oauth2Client.getToken(q.code);
      oauth2Client.setCredentials(tokens);

      // Example of using Google Drive API to list filenames in user's Drive.
      const drive = google.drive('v3');
      drive.files.list({
        auth: oauth2Client,
        pageSize: 10,
        fields: 'nextPageToken, files(id, name)',
      }, (err1, res1) => {
        // TODO(developer): Handle response / error.
      });
    }
  }
}

راجِع دليل تطبيقات الويب من جهة الخادم للتعرّف على كيفية الوصول إلى واجهات Google API من جهة الخادم.

الوصول من جهة العميل

يعرض مقتطف الرمز البرمجي أدناه، المكتوب بلغة JavaScript، مثالاً على استخدام Google API للوصول إلى أحداث تقويم المستخدم من جهة العميل.


// initTokenClient() initializes a new token client with your
// web app's client ID and the scope you need access to

const client = google.accounts.oauth2.initTokenClient({
  client_id: 'YOUR_GOOGLE_CLIENT_ID',
  scope: 'https://www.googleapis.com/auth/calendar.readonly',
  
  // callback function to handle the token response
  callback: (tokenResponse) => {
    if (tokenResponse && tokenResponse.access_token) { 
      gapi.client.setApiKey('YOUR_API_KEY');
      gapi.client.load('calendar', 'v3', listUpcomingEvents);
    }
  },
});

function listUpcomingEvents() {
  gapi.client.calendar.events.list(...);
}

راجِع دليل تطبيقات الويب من جهة العميل للتعرّف على كيفية الوصول إلى واجهات Google API من جهة العميل.

برنامج الكمبيوتر

إذا تبيّن لك أنّ تطبيقك يستخدم مسار OOB على جهاز كمبيوتر، عليك الانتقال إلى استخدام مسار عنوان IP الاسترجاع (localhost أو 127.0.0.1).