دليل مطوّري برامج إمكانية الدخول المعتمَد إلى Chrome

لمحة عن هذا الدليل

تسمح واجهة برمجة التطبيقات لإمكانية الدخول المعتمد في Chrome بخدمات الشبكة، مثل الشبكات الظاهرية الخاصة والشبكات الداخلية وما إلى ذلك للتأكد من أن عملائهم صادقين بطريقة مشفرة تلتزم بسياسة الشركة. تطلب معظم الشركات الكبرى السماح للأجهزة التي تديرها المؤسسات فقط بالوصول إلى شبكات WPA2 EAP-TLS، مستوى وصول أعلى في الشبكات الافتراضية الخاصة وصفحات الشبكات الداخلية المتبادلة لبروتوكول أمان طبقة النقل (TLS). العديد من النتائج الحالية على عمليات الفحص الإرشادية على العميل نفسه الذي ربما تم اختراق البيانات. وهذا يمثل التحدي المتمثل في الاعتماد على الإشارات التي يتم الاعتماد عليها بإثبات الحالة المشروعة للجهاز في حد ذاته مزيف. يقدم هذا الدليل ضمانات تشفير مستندة إلى الأجهزة هوية الجهاز وأنّ حالته غير معدّلة ومتوافقة مع السياسة عند التشغيل يسمى الدخول المعتمد.

الجمهور الأساسي مشرفو نطاقات تكنولوجيا المعلومات للمؤسسات
المكوّنات الفنية نظام التشغيل ChromeOS وواجهة برمجة التطبيقات لإمكانية الوصول المعتمد من Google

المتطلبات الأساسية للدخول المُتحقَّق منه

أكمل الإعداد التالي قبل تنفيذ عملية الدخول المعتمد.

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

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

  1. إنشاء مشروع حالي أو استخدامه في وحدة التحكم في واجهة Google API:
  2. الانتقال إلى قسم واجهات برمجة التطبيقات المفعّلة الخدمات.
  3. فعِّل واجهة برمجة تطبيقات الوصول المعتمَد في Chrome.
  4. أنشِئ مفتاح واجهة برمجة تطبيقات لتطبيقك باتّباع مستندات Google Cloud API.

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

ولكي تتمكّن خدمة الشبكة من الوصول إلى واجهة برمجة التطبيقات لإمكانية الدخول المعتمد في Chrome للتحقّق من والاستجابة للتحدي إنشاء حساب خدمة ومفتاح حساب خدمة (لن تحتاج إلى إنشاء مشروع جديد على السحابة الإلكترونية، ويمكنك استخدام المشروع نفسه).

بعد إنشاء مفتاح حساب الخدمة، من المفترض أن يصبح لديك حساب خدمة. تم تنزيل ملف المفتاح الخاص. وهذه هي النسخة الوحيدة من المفتاح الخاص، لذا يجب فتأكد من تخزينها بأمان.

تسجيل جهاز Chromebook مُدار

عليك إعداد جهاز Chromebook مُدار بشكل صحيح باستخدام متصفّح Chrome. للإضافة لإمكانية الدخول المعتمد.

  1. يجب أن يكون جهاز Chromebook مُسجَّلاً في إدارة المؤسسات أو التعليم.
  2. يجب أن يكون مستخدِم الجهاز مستخدمًا مسجَّلاً من النطاق نفسه.
  3. يجب تثبيت إضافة Chrome على الجهاز لميزة "الوصول الذي تم التحقّق منه".
  4. يتم ضبط السياسات لتفعيل إمكانية الدخول المعتمد، وإدراج Chrome في القائمة المسموح بها امتداد، ومنح الوصول إلى واجهة برمجة التطبيقات لحساب الخدمة الذي يمثل خدمة الشبكة (راجع مستندات مساعدة "وحدة تحكّم المشرف في Google").

التحقق من المستخدم والجهاز

يمكن للمطوّرين استخدام ميزة "الوصول المتحقَّق منه" للتحقّق من المستخدم أو الجهاز، أو استخدام كليهما لتعزيز الأمان:

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

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

كيفية التحقق من المستخدم والجهاز

  1. الحصول على تحدٍ: إضافة Chrome على الجهاز إلى جهة الاتصال التي تم التحقق منها يمكنك الوصول إلى واجهة برمجة التطبيقات للحصول على تحدٍ. التحدي هو عدم وضوح البيانات هو بنية (كائنات ثنائية كبيرة موقَّعة من Google) صالحة لمدة دقيقة واحدة، بمعنى ويفشل التحقق من الاستجابة للتحدي (الخطوة 3) في حال استخدام تحدٍ قديم.

    في أبسط حالة استخدام، يبدأ المستخدم هذا التدفق بالنقر فوق الزر الذي تُنشئه الإضافة (وهو أيضًا نموذج الإضافة التي توفّرها Google يفعل).

    var apiKey = 'YOUR_API_KEY_HERE';
    var challengeUrlString =
      'https://verifiedaccess.googleapis.com/v2/challenge:generate?key=' + apiKey;
    
    // Request challenge from URL
    var xmlhttp = new XMLHttpRequest();
    xmlhttp.open('POST', challengeUrlString, true);
    xmlhttp.send();
    xmlhttp.onreadystatechange = function() {
      if (xmlhttp.readyState == 4) {
        var challenge = xmlhttp.responseText;
        console.log('challenge: ' + challenge);
        // v2 of the API returns an encoded challenge so no further challenge processing is needed
      }
    };
    

    رمز مساعد لترميز التحدي: إذا كنت تستخدم الإصدار 1 من واجهة برمجة التطبيقات، سيكون لديك ترميزه.

    // This can be replaced by using a third-party library such as
    // [https://github.com/dcodeIO/ProtoBuf.js/wiki](https://github.com/dcodeIO/ProtoBuf.js/wiki)
    /**
     * encodeChallenge convert JSON challenge into base64 encoded byte array
     * @param {string} challenge JSON encoded challenge protobuf
     * @return {string} base64 encoded challenge protobuf
     */
    var encodeChallenge = function(challenge) {
      var jsonChallenge = JSON.parse(challenge);
      var challengeData = jsonChallenge.challenge.data;
      var challengeSignature = jsonChallenge.challenge.signature;
    
      var protobufBinary = protoEncodeChallenge(
          window.atob(challengeData), window.atob(challengeSignature));
    
      return window.btoa(protobufBinary);
    };
    
    /**
     * protoEncodeChallenge produce binary encoding of the challenge protobuf
     * @param {string} dataBinary binary data field
     * @param {string} signatureBinary binary signature field
     * @return {string} binary encoded challenge protobuf
     */
    var protoEncodeChallenge = function(dataBinary, signatureBinary) {
      var protoEncoded = '';
    
      // See https://developers.google.com/protocol-buffers/docs/encoding
      // for encoding details.
    
      // 0x0A (00001 010, field number 1, wire type 2 [length-delimited])
      protoEncoded += '\u000A';
    
      // encode length of the data
      protoEncoded += varintEncode(dataBinary.length);
      // add data
      protoEncoded += dataBinary;
    
      // 0x12 (00010 010, field number 2, wire type 2 [length-delimited])
      protoEncoded += '\u0012';
      // encode length of the signature
      protoEncoded += varintEncode(signatureBinary.length);
      // add signature
      protoEncoded += signatureBinary;
    
      return protoEncoded;
    };
    
    /**
     * varintEncode produce binary encoding of the integer number
     * @param {number} number integer number
     * @return {string} binary varint-encoded number
     */
    var varintEncode = function(number) {
      // This only works correctly for numbers 0 through 16383 (0x3FFF)
      if (number <= 127) {
        return String.fromCharCode(number);
      } else {
        return String.fromCharCode(128 + (number & 0x7f), number >>> 7);
      }
    };
    
  2. إنشاء استجابة للتحدي: تستخدم إضافة Chrome التحدي الذي تواجهه الذي تم استلامه في الخطوة 1 لطلب واجهة برمجة تطبيقات Chrome Enterprise.platformKeys. هذا النمط ينشئ ردًّا موقَّعًا ومشفّرًا للتحدي، تتولى الإضافة يتضمن طلب الوصول الذي يرسله إلى خدمة الشبكة.

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

    في ما يلي رمز نموذجي لإنشاء ردّ على التحدي:

    إنشاء ردّ بشأن التحدّي

      // Generate challenge response
      var encodedChallenge; // obtained by generate challenge API call
      try {
        if (isDeviceVerification) { // isDeviceVerification set by external logic
          chrome.enterprise.platformKeys.challengeKey(
              {
                scope: 'MACHINE',
                challenge: decodestr2ab(encodedChallenge),
              },
              ChallengeCallback);
        } else {
          chrome.enterprise.platformKeys.challengeKey(
              {
                scope: 'USER',
                challenge: decodestr2ab(encodedChallenge),
                registerKey: { 'RSA' }, // can also specify 'ECDSA'
              },
              ChallengeCallback);
        }
      } catch (error) {
        console.log('ERROR: ' + error);
      }
    

    دالة معاودة الاتصال للتحدي

      var ChallengeCallback = function(response) {
        if (chrome.runtime.lastError) {
          console.log(chrome.runtime.lastError.message);
        } else {
          var responseAsString = ab2base64str(response);
          console.log('resp: ' + responseAsString);
        ... // send on to network service
       };
      }
    

    الرمز المساعِد لتحويل ArrayBuffer

      /**
       * ab2base64str convert an ArrayBuffer to base64 string
       * @param {ArrayBuffer} buf ArrayBuffer instance
       * @return {string} base64 encoded string representation
       * of the ArrayBuffer
       */
      var ab2base64str = function(buf) {
        var binary = '';
        var bytes = new Uint8Array(buf);
        var len = bytes.byteLength;
        for (var i = 0; i < len; i++) {
          binary += String.fromCharCode(bytes[i]);
        }
        return window.btoa(binary);
      }
    
      /**
       * decodestr2ab convert a base64 encoded string to ArrayBuffer
       * @param {string} str string instance
       * @return {ArrayBuffer} ArrayBuffer representation of the string
       */
      var decodestr2ab = function(str) {
        var binary_string =  window.atob(str);
        var len = binary_string.length;
        var bytes = new Uint8Array(len);
        for (var i = 0; i < len; i++)        {
            bytes[i] = binary_string.charCodeAt(i);
        }
        return bytes.buffer;
      }
    
  3. التحقق من الرد على التحدي: عند تلقي رد على التحدي من الجهاز (ربما كامتداد لبروتوكول المصادقة الحالي)، خدمة الشبكة الاتصال بواجهة برمجة تطبيقات الدخول المعتمد للتحقق من الجهاز الهوية ووضع السياسة (اطّلِع على مثال الرمز أدناه). لمكافحة الانتحال، توصي خدمة الشبكة بتحديد العميل الذي تتحدث إليه يجب تضمين الهوية المتوقعة للعميل في طلبه:

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

    عند استدعاء واجهة برمجة التطبيقات Google API، يتم إجراء عدد من عمليات الفحص، مثل:

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

    يستخدم هذا المثال مكتبة gRPC

    import com.google.auth.oauth2.GoogleCredentials;
    import com.google.auth.oauth2.ServiceAccountCredentials;
    import com.google.chrome.verifiedaccess.v2.VerifiedAccessGrpc;
    import com.google.chrome.verifiedaccess.v2.VerifyChallengeResponseRequest;
    import com.google.chrome.verifiedaccess.v2.VerifyChallengeResponseResult;
    import com.google.protobuf.ByteString;
    
    import io.grpc.ClientInterceptor;
    import io.grpc.ClientInterceptors;
    import io.grpc.ManagedChannel;
    import io.grpc.auth.ClientAuthInterceptor;
    import io.grpc.netty.GrpcSslContexts;
    import io.grpc.netty.NettyChannelBuilder;
    
    import java.io.File;
    import java.io.FileInputStream;
    import java.util.Arrays;
    import java.util.concurrent.Executors;
    
    // https://cloud.google.com/storage/docs/authentication#generating-a-private-key
    private final String clientSecretFile = "PATH_TO_GENERATED_JSON_SECRET_FILE";
    
    private ManagedChannel channel;
    private VerifiedAccessGrpc.VerifiedAccessBlockingStub client;
    
    void setup() {
    
       channel = NettyChannelBuilder.forAddress("verifiedaccess.googleapis.com", 443)
          .sslContext(GrpcSslContexts.forClient().ciphers(null).build())
          .build();
    
       List<ClientInterceptor> interceptors = Lists.newArrayList();
       // Attach a credential for my service account and scope it for the API.
       GoogleCredentials credentials =
           ServiceAccountCredentials.class.cast(
               GoogleCredentials.fromStream(
                   new FileInputStream(new File(clientSecretFile))));
      credentials = credentials.createScoped(
          Arrays.<String>asList("https://www.googleapis.com/auth/verifiedaccess"));
      interceptors.add(
           new ClientAuthInterceptor(credentials, Executors.newSingleThreadExecutor()));
    
      // Create a stub bound to the channel with the interceptors applied
      client = VerifiedAccessGrpc.newBlockingStub(
          ClientInterceptors.intercept(channel, interceptors));
    }
    
    /**
     * Invokes the synchronous RPC call that verifies the device response.
     * Returns the result protobuf as a string.
     *
     * @param signedData base64 encoded signedData blob (this is a response from device)
     * @param expectedIdentity expected identity (domain name or user email)
     * @return the verification result protobuf as string
     */
    public String verifyChallengeResponse(String signedData, String expectedIdentity)
      throws IOException, io.grpc.StatusRuntimeException {
      VerifyChallengeResponseResult result =
        client.verifyChallengeResponse(newVerificationRequest(signedData,
            expectedIdentity)); // will throw StatusRuntimeException on error.
    
      return result.toString();
    }
    
    private VerifyChallengeResponseRequest newVerificationRequest(
      String signedData, String expectedIdentity) throws IOException {
      return VerifyChallengeResponseRequest.newBuilder()
        .setChallengeResponse(
            ByteString.copyFrom(BaseEncoding.base64().decode(signedData)))
        .setExpectedIdentity(expectedIdentity == null ? "" : expectedIdentity)
        .build();
    }
    
  4. منح إمكانية الوصول: هذه الخطوة أيضًا خاصة بخدمة الشبكة. هذا هو التنفيذ المقترح (غير الموصوف). تشمل الإجراءات المحتملة ما يلي:

    • إنشاء ملف تعريف ارتباط لجلسة
    • إصدار شهادة للمستخدم أو الجهاز في حالة وجود مستخدم ناجح التحقق، وبافتراض أن خدمة الشبكة قد تم منحها حق الوصول إلى بيانات المستخدمين الإضافية (عبر سياسة وحدة تحكُّم المشرف في Google)، فإنها CSR موقع من المستخدم، والذي يمكن استخدامه بعد ذلك للحصول على طلب توقيع الشهادة شهادة من هيئة إصدار الشهادات. عند الدمج مع MicrosoftR CA، يمكن لخدمة الشبكة أن تعمل والاستفادة من واجهة ICertRequest.

استخدام شهادات العميل مع إمكانية الدخول المعتمد

استخدام شهادات العميل مع إمكانية الدخول المعتمد.

في المؤسسات الكبيرة، قد يكون هناك العديد من خدمات الشبكة (خوادم الشبكة الظاهرية الخاصة، ونقاط وصول Wi-Fi، وبرامج جدار الحماية، ومواقع الشبكة الداخلية المتعددة) التي ستستفيد من إمكانية الدخول المعتمد. ومع ذلك، فإن بناء منطق الخطوات من 2 إلى 4 (في القسم أعلاه) في كل خدمة من خدمات الشبكة هذه عملية. وغالبًا ما يتمتع العديد من خدمات الشبكة هذه بإمكانية طلب شهادات العميل كجزء من مصادقاته (على سبيل المثال، صفحات EAP-TLS أو الشبكة الداخلية المتبادلة لبروتوكول أمان طبقة النقل (TLS). لذلك إذا كانت شهادة المؤسسة يمكن للسلطة التي تُصدر شهادات العميل هذه تنفيذ الخطوات من 2 إلى 4 شرط إصدار شهادة العميل على الاستجابة للتحدي إثبات الملكية، فيمكن أن يكون حيازة الشهادة دليلاً على أن العميل صادق ويتوافق مع سياسة الشركة. بعد ذلك، كل شبكة Wi-Fi نقطة الوصول، وخادم VPN، وما إلى ذلك، للتحقق من شهادة العميل هذه بدلاً من الحاجة إلى اتباع الخطوات من 2 إلى 4.

بعبارة أخرى، هنا مرجع التصديق (الذي يُصدر شهادة العميل إلى المؤسسة) خدمة الشبكة في الشكل 1. يجب استدعاء واجهة برمجة التطبيقات لإمكانية الوصول المعتمد، وبعد التحقق من الاستجابة للتحدي فقط تمرير الشهادة، أو تقديم الشهادة للعميل. إن تقديم الشهادة إلى معنى العميل هي الخطوة 4 - منح حق الوصول في الشكل 1.

توضيح عملية الحصول على شهادات العميل بأمان على أجهزة Chromebook الواردة في هذه المقالة. إذا كانت التصميم الموصوف في هذه الفقرة، ثم "إضافة إمكانية الوصول المعتمد" ويمكن دمج إضافة إعداد شهادة العميل في إضافة واحدة. مزيد من المعلومات حول كيفية كتابة إضافة إعداد شهادة عميل.