Panduan Developer Akses Terverifikasi Chrome

Tentang panduan ini

Chrome Verified Access API memungkinkan layanan jaringan, seperti VPN, halaman intranet, dan sebagainya untuk memverifikasi secara kriptografis bahwa klien mereka asli dan sesuai dengan kebijakan perusahaan. Sebagian besar perusahaan besar memiliki persyaratan untuk hanya mengizinkan perangkat yang dikelola perusahaan ke jaringan WPA2 EAP-TLS mereka, akses dengan tingkat yang lebih tinggi di VPN, dan halaman intranet bersama-TLS. Banyak solusi yang ada mengandalkan pemeriksaan heuristik pada klien yang sama yang mungkin telah disusupi. Hal ini menimbulkan tantangan bahwa sinyal yang diandalkan untuk membuktikan status sah perangkat itu sendiri mungkin telah dipalsukan. Panduan ini memberikan jaminan kriptografi yang didukung hardware untuk identitas perangkat dan bahwa statusnya tidak dimodifikasi dan mematuhi 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 proyek konsol API Google dan aktifkan API:

  1. Buat atau gunakan project yang sudah ada di konsol API Google.
  2. Buka halaman Enabled APIs & services.
  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, buat akun layanan dan kunci akun layanan (Anda tidak perlu membuat project Cloud baru, Anda dapat menggunakan yang sama).

Setelah membuat kunci akun layanan, Anda seharusnya sudah mendownload file kunci pribadi akun layanan. Ini adalah satu-satunya salinan kunci pribadi, jadi pastikan untuk menyimpannya dengan aman.

Mendaftarkan perangkat Chromebook terkelola

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

  1. Perangkat Chromebook harus terdaftar untuk pengelolaan perusahaan atau pendidikan.
  2. Pengguna perangkat harus merupakan pengguna terdaftar dari domain yang sama.
  3. Ekstensi Chrome untuk Akses Terverifikasi harus diinstal di perangkat.
  4. Kebijakan dikonfigurasi untuk mengaktifkan Akses Terverifikasi, mengizinkan ekstensi Chrome, 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 jaminan bahwa perangkat Chrome terdaftar di domain terkelola dan sesuai dengan kebijakan perangkat mode booting terverifikasi seperti yang ditentukan oleh administrator domain. Jika layanan jaringan diberi izin untuk melihat identitas perangkat (lihat dokumentasi Bantuan konsol Google Admin), layanan tersebut juga akan menerima ID perangkat yang dapat digunakan untuk mengaudit, melacak, atau memanggil Directory API.

  • Verifikasi pengguna—Jika berhasil, verifikasi pengguna akan memberikan jaminan bahwa pengguna Chrome yang login adalah pengguna terkelola, menggunakan perangkat terdaftar, dan mematuhi kebijakan pengguna mode booting terverifikasi seperti yang ditentukan oleh administrator domain. Jika layanan jaringan diberi izin untuk menerima data pengguna tambahan, layanan tersebut juga akan mendapatkan permintaan penandatanganan sertifikat yang dikeluarkan oleh pengguna (CSR dalam bentuk signature-public-key-and-challenge, atau SPKAC, juga dikenal sebagai format keygen).

Cara memverifikasi pengguna dan perangkat

  1. Mendapatkan tantangan—Ekstensi Chrome di perangkat menghubungi Verified Access API untuk mendapatkan tantangan. Tantangannya adalah struktur data buram (blob yang ditandatangani Google) yang berlaku selama 1 menit, yang berarti verifikasi respons tantangan (langkah 3) akan gagal jika tantangan yang sudah tidak berlaku digunakan.

    Dalam kasus penggunaan yang paling sederhana, pengguna memulai alur ini dengan mengklik tombol yang dihasilkan oleh ekstensi (ini juga yang dilakukan oleh 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 helper untuk mengenkode tantangan—Jika Anda menggunakan API v1, tantangan 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. Buat respons tantangan—Ekstensi Chrome menggunakan tantangan yang diterima pada langkah 1 untuk memanggil API Chrome enterprise.platformKeys. Tindakan ini akan menghasilkan respons tantangan yang ditandatangani dan dienkripsi, yang disertakan oleh ekstensi dalam permintaan akses yang dikirimkan ke layanan jaringan.

    Pada langkah ini, tidak ada upaya untuk menentukan protokol yang digunakan ekstensi dan layanan jaringan untuk berkomunikasi. Kedua entity ini diterapkan oleh developer eksternal dan tidak ditentukan cara keduanya berkomunikasi satu sama lain. Contohnya adalah mengirim respons tantangan (dienkode URL) sebagai parameter string kueri, menggunakan HTTP POST, atau menggunakan 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 helper 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. Verify challenge response—Setelah menerima respons tantangan dari perangkat (mungkin sebagai ekstensi ke protokol autentikasi yang ada), layanan jaringan harus memanggil Verified Access API untuk memverifikasi identitas perangkat dan postur kebijakan (lihat kode contoh di bawah). Untuk mengatasi spoofing, sebaiknya layanan jaringan mengidentifikasi klien yang diajak berkomunikasi dan menyertakan identitas klien yang diharapkan dalam permintaannya:

    • Untuk verifikasi perangkat, domain perangkat yang diharapkan harus diberikan . Dalam banyak kasus, nilai ini kemungkinan merupakan nilai hard code karena layanan jaringan melindungi resource untuk domain tertentu. Jika tidak diketahui sebelumnya, hal ini dapat disimpulkan dari identitas pengguna.
    • Untuk verifikasi pengguna, alamat email pengguna yang diharapkan harus disediakan. Kami berharap layanan jaringan mengetahui penggunanya (biasanya pengguna akan diminta untuk login).

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

    • Pastikan respons tantangan dibuat oleh ChromeOS dan tidak diubah saat dalam pengiriman
    • Pastikan perangkat atau pengguna dikelola perusahaan.
    • Verifikasi bahwa identitas perangkat/pengguna cocok dengan identitas yang diharapkan (jika disediakan).
    • Verifikasi bahwa tantangan yang ditanggapi adalah baru (berdurasi tidak lebih dari 1 menit).
    • Verifikasi bahwa perangkat atau pengguna mematuhi kebijakan seperti yang ditentukan oleh administrator domain.
    • Pastikan pemanggil (layanan jaringan) diberi izin untuk memanggil API.
    • Jika pemanggil diberi izin untuk memperoleh data pengguna atau perangkat tambahan, sertakan ID perangkat atau permintaan penandatanganan sertifikat (CSR) pengguna dalam respons.

    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 berlaku khusus untuk layanan jaringan. Ini adalah penerapan yang disarankan (tidak ditentukan). Tindakan yang dapat dilakukan adalah:

    • Pembuatan cookie sesi
    • Memberikan sertifikat untuk pengguna atau perangkat. Jika verifikasi pengguna berhasil, dan dengan asumsi bahwa layanan jaringan telah diberi akses ke data pengguna tambahan (melalui kebijakan konsol Google Admin), layanan ini akan menerima CSR yang ditandatangani pengguna, yang kemudian dapat digunakan untuk mendapatkan sertifikat aktual dari otoritas sertifikasi. Saat berintegrasi dengan CA Microsoft, layanan jaringan dapat bertindak sebagai perantara dan menggunakan antarmuka ICertRequest.

Menggunakan sertifikat klien dengan Akses Terverifikasi

Menggunakan sertifikat klien dengan Akses Terverifikasi.

Dalam organisasi besar, mungkin ada beberapa layanan jaringan (server VPN, titik akses Wi-Fi, firewall, dan beberapa situs intranet) yang akan mendapatkan 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 layanan jaringan ini sudah memiliki kemampuan untuk mewajibkan sertifikat klien sebagai bagian dari autentikasinya (misalnya, EAP-TLS atau halaman intranet TLS bersama). Jadi, jika Enterprise Certificate Authority yang menerbitkan sertifikat klien ini dapat menerapkan langkah 2–4 dan menentukan penerbitan sertifikat klien pada verifikasi tantangan-respons, kepemilikan sertifikat tersebut dapat menjadi bukti bahwa klien tersebut asli dan sesuai dengan kebijakan perusahaan. Setelah itu, setiap titik akses Wi-Fi, server VPN, dan sebagainya dapat memeriksa sertifikat klien ini, tanpa perlu mengikuti langkah 2–4.

Dengan kata lain, di sini CA (yang menerbitkan sertifikat klien ke perangkat perusahaan) berperan sebagai Layanan Jaringan pada Gambar 1. Klien perlu memanggil Verified Access API dan, hanya setelah verifikasi respons tantangan lulus, berikan sertifikat kepada klien. Memberikan sertifikat kepada klien setara dengan langkah 4 - Memberikan Akses pada Gambar 1.

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