دليل نقل التدفق خارج النطاق (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 Cloud Console.

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

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

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

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

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

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

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

راجِع قسم الرمز البرمجي للتطبيق الذي ترسل فيه طلبات إلى نقاط نهاية تفويض 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 APIs بدون استخدام معرّف URI لإعادة التوجيه خارج النطاق.

الوصول إلى Google APIs على Android

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

يوضّح المثال التالي كيفية الوصول إلى Google APIs من جهة العميل على Android باستخدام مكتبة "خدمات هوية Google" المقترَحة على 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 APIs من جهة الخادم على 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 APIs في تطبيق 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)، أو باستخدام أداة التفويض في برنامج الجلب (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 APIs من جهة الخادم.

برنامج عميل تطبيقات Chrome

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

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

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 API للغات البرمجة المختلفة.

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

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

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

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 APIs من جهة الخادم.

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

تعرض مقتطفة الرمز البرمجي التالية، بلغة 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 APIs من جهة العميل.

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

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