Panduan Developer Akses Terverifikasi Chrome

Tentang panduan ini

Chrome Verified Access API memungkinkan layanan jaringan, seperti VPN, dan sebagainya untuk memverifikasi secara kriptografi bahwa klien mereka asli mematuhi kebijakan perusahaan. Sebagian besar perusahaan besar harus hanya mengizinkan perangkat yang dikelola perusahaan ke jaringan WPA2 EAP-TLS mereka, akses yang lebih tinggi di VPN, dan halaman intranet TLS bersama. Banyak yang sudah mengandalkan pemeriksaan heuristik pada klien yang sama yang disusupi. Hal ini menghadirkan tantangan bahwa sinyal yang diandalkan untuk mengesahkan status sah dari perangkat itu sendiri telah dipalsukan. Panduan ini memberikan jaminan kriptografi yang didukung perangkat keras atas identitas perangkat dan bahwa statusnya tidak dimodifikasi serta sesuai dengan kebijakan saat booting; yang disebut Akses Terverifikasi.

Audiens utama Administrator domain IT perusahaan
Komponen teknis ChromeOS, Google Verified Access API

Prasyarat untuk Akses Terverifikasi

Selesaikan penyiapan berikut sebelum menerapkan proses Akses Terverifikasi.

Mengaktifkan API

Siapkan project konsol API Google dan aktifkan API tersebut:

  1. Buat atau gunakan project yang sudah ada di Konsol API Google.
  2. Buka halaman API yang diaktifkan & layanan Google.
  3. Aktifkan Chrome Verified Access API.
  4. Buat kunci API untuk aplikasi Anda dengan mengikuti dokumentasi Google Cloud API.

Membuat akun layanan

Agar layanan jaringan dapat mengakses Chrome Verified Access API untuk memverifikasi respons tantangan, membuat akun layanan dan kunci akun layanan (Anda tidak perlu membuat project Cloud baru, Anda dapat menggunakan project yang sama).

Setelah membuat kunci akun layanan, Anda akan memiliki akun layanan file kunci pribadi yang diunduh. Ini adalah satu-satunya salinan kunci pribadi, jadi pastikan pastikan Anda menyimpannya dengan aman.

Mendaftarkan perangkat Chromebook terkelola

Anda memerlukan penyiapan perangkat Chromebook yang dikelola dengan benar di Chrome ekstensi untuk Akses Terverifikasi.

  1. Perangkat Chromebook harus terdaftar untuk pengelolaan perusahaan atau pendidikan.
  2. Pengguna perangkat harus merupakan pengguna yang terdaftar dari domain yang sama.
  3. Ekstensi Chrome untuk Akses Terverifikasi harus diinstal di perangkat.
  4. Kebijakan dikonfigurasi untuk mengaktifkan Akses Terverifikasi, mengizinkan Chrome ekstensi, dan memberikan akses ke API untuk akun layanan yang mewakili layanan jaringan (lihat Dokumentasi Bantuan konsol Google Admin).

Verifikasi pengguna dan perangkat

Developer dapat menggunakan Akses Terverifikasi untuk verifikasi pengguna atau perangkat, atau menggunakan keduanya untuk keamanan tambahan:

  • Verifikasi perangkat—Jika berhasil, verifikasi perangkat akan memberikan pastikan bahwa perangkat Chrome terdaftar di domain terkelola dan mematuhi kebijakan perangkat mode booting terverifikasi sebagaimana ditentukan oleh domain Google Workspace for Education. Jika layanan jaringan diberi izin untuk melihat perangkat (lihat dokumentasi Bantuan konsol Google Admin), lalu ID tersebut juga akan menerima ID perangkat yang dapat digunakan untuk mengaudit, melacak, atau memanggil Directory API.

  • Verifikasi pengguna—Jika berhasil, verifikasi pengguna memberikan jaminan bahwa pengguna Chrome yang login adalah pengguna terkelola, menggunakan perangkat terdaftar, dan mematuhi kebijakan pengguna mode booting terverifikasi sebagaimana ditentukan oleh domain Google Workspace for Education. Jika layanan jaringan diberikan izin untuk menerima data pengguna tambahan, mereka juga akan memperoleh permintaan penandatanganan sertifikat yang diterbitkan oleh pengguna (CSR dalam bentuk {i>signed-public-key-and-challenge<i}, atau SPKAC, juga dikenal sebagai format keygen).

Cara memverifikasi pengguna dan perangkat

  1. Dapatkan tantangan—Ekstensi Chrome di perangkat menghubungi Verifikasi Akses API untuk mendapatkan tantangan. Tantangannya adalah data yang tidak transparan (blob yang ditandatangani Google) yang berlaku selama 1 menit, yang berarti verifikasi respons tantangan (langkah 3) gagal jika tantangan yang sudah tidak berlaku digunakan.

    Dalam kasus penggunaan yang paling sederhana, pengguna memulai alur ini dengan mengklik tombol yang yang dihasilkan ekstensi (ini juga merupakan ekstensi contoh yang disediakan 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
      }
    };
    

    Kode bantuan untuk mengenkode tantangan—Jika Anda menggunakan API v1, harus dienkode.

    // 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. Membuat respons tantangan—Ekstensi Chrome menggunakan tantangan yang diterima pada langkah 1 untuk memanggil Chrome API enterprise.platformKeys. Ini menghasilkan respons verifikasi yang ditandatangani dan dienkripsi, disertakan dalam permintaan akses yang dikirimnya ke layanan jaringan.

    Pada langkah ini, tidak ada upaya untuk menentukan protokol yang ekstensi dan penggunaan layanan jaringan untuk berkomunikasi. Kedua entitas ini diterapkan oleh pengembang eksternal dan tidak ditentukan bagaimana mereka berkomunikasi satu sama lain. Channel contohnya adalah mengirim respons tantangan (dienkodekan URL) sebagai string kueri menggunakan HTTP POST, atau header HTTP khusus.

    Berikut adalah kode contoh untuk membuat respons tantangan:

    Membuat respons tantangan

      // 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);
      }
    

    Fungsi callback tantangan

      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
       };
      }
    

    Kode bantuan untuk konversi 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. Verifikasi respons tantangan—Setelah menerima respons tantangan dari perangkat (mungkin sebagai ekstensi ke protokol otentikasi yang ada), layanan jaringan harus memanggil Verified Access API untuk memverifikasi perangkat identitas dan postur kebijakan (lihat kode contoh di bawah). Untuk melawan spoofing, kami merekomendasikan agar layanan jaringan mengidentifikasi klien yang berbicara dengannya dan mencantumkan identitas klien yang diharapkan dalam permintaannya:

    • Untuk verifikasi perangkat, domain perangkat yang diharapkan harus diberikan kami. Dalam banyak kasus, ini mungkin merupakan nilai {i>hard-code<i}, karena jaringan {i>service<i} melindungi sumber daya untuk domain tertentu. Jika hal ini tidak diketahui sebelumnya, hal itu dapat disimpulkan dari identitas pengguna.
    • Untuk verifikasi pengguna, alamat email pengguna yang diharapkan harus yang Anda berikan. Kami berharap layanan jaringan mengetahui penggunanya (biasanya mengharuskan pengguna untuk login).

    Saat dipanggil, Google API akan melakukan sejumlah pemeriksaan, seperti:

    • Pastikan respons tantangan dibuat oleh ChromeOS dan bukan diubah saat transit
    • Pastikan perangkat atau pengguna dikelola perusahaan.
    • Verifikasi bahwa identitas perangkat/pengguna cocok dengan yang diharapkan identitas Anda (jika yang terakhir disediakan).
    • Verifikasi bahwa tantangan yang ditanggapi adalah baru (tidak lebih dari 1 menit).
    • Verifikasi bahwa perangkat atau pengguna mematuhi kebijakan yang ditentukan oleh administrator domain.
    • Memastikan pemanggil (layanan jaringan) diberi izin untuk menelepon API.
    • Jika penelepon diberi izin untuk mendapatkan perangkat tambahan atau data pengguna, sertakan ID perangkat atau penandatanganan sertifikat pengguna (CSR) dalam responsnya.

    Contoh ini menggunakan library 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. Berikan akses—Langkah ini juga khusus untuk layanan jaringan. Ini adalah implementasi yang disarankan (tidak ditentukan). Tindakan yang mungkin dilakukan adalah:

    • Pembuatan cookie sesi
    • Menerbitkan sertifikat untuk pengguna atau perangkat. Jika pengguna berhasil verifikasi, dan menganggap layanan jaringan telah diberi akses ke data pengguna tambahan (melalui kebijakan konsol Google Admin), menerima CSR yang ditandatangani pengguna, yang kemudian dapat digunakan untuk mendapatkan sertifikat dari otoritas sertifikasi. Ketika mengintegrasikan dengan MicrosoftR CA, layanan jaringan dapat berfungsi sebagai perantara dan memanfaatkan antarmuka ICertRequest.

Menggunakan sertifikat klien dengan Akses Terverifikasi

Menggunakan sertifikat klien dengan Akses Terverifikasi.

Di organisasi besar, mungkin ada beberapa layanan jaringan (server VPN, titik akses Wi-Fi, {i>firewall<i}, dan beberapa situs intranet) yang akan mendapat manfaat dari Akses Terverifikasi. Namun, membangun logika langkah 2–4 (di bagian di atas) di setiap layanan jaringan ini mungkin tidak praktis. Sering kali, banyak dari layanan jaringan ini sudah memiliki kemampuan untuk memerlukan sertifikat klien sebagai bagian dari otentikasi mereka (misalnya, EAP-TLS atau halaman intranet TLS bersama). Jadi, jika Sertifikat Perusahaan Otoritas yang menerbitkan sertifikat klien ini dapat menerapkan langkah 2–4 dan ketentuan penerbitan sertifikat klien pada respons tantangan verifikasi, maka kepemilikan sertifikat bisa menjadi bukti bahwa klien itu asli dan sesuai dengan kebijakan perusahaan. Setelah itu, setiap Wi-Fi titik akses, server VPN, dan sebagainya dapat memeriksa sertifikat klien ini daripada harus mengikuti langkah 2-4.

Dengan kata lain, di sini CA (yang menerbitkan sertifikat klien ke perusahaan perangkat) berperan sebagai Layanan Jaringan di Gambar 1. Aplikasi perlu memanggil {i>Verified Access API<i} dan, hanya setelah verifikasi respons tantangan lulus, memberikan sertifikatnya ke klien. Memberikan sertifikat kepada klien adalah setara dengan Langkah 4 - {i> Grant Access<i} di Gambar 1.

Proses mendapatkan sertifikat klien dengan aman ke Chromebook dijelaskan dalam artikel ini. Jika desain yang dijelaskan dalam paragraf ini diikuti, maka Ekstensi Akses Terverifikasi dan Ekstensi orientasi sertifikat klien dapat digabungkan menjadi satu. Pelajari lebih lanjut tentang cara menulis ekstensi orientasi sertifikat klien.