Guía para desarrolladores sobre el acceso verificado de Chrome

Acerca de esta guía

La API de Chrome Verified Access permite servicios de red, como VPN, intranet y así sucesivamente, para verificar criptográficamente que sus clientes son genuinos y cumplir con la política corporativa. La mayoría de las grandes empresas tienen el requisito permitir que solo dispositivos administrados por empresas accedan a sus redes WPA2 EAP-TLS, acceso de mayor nivel en VPN y páginas de intranet con TLS mutua. Muchos existentes se basan en verificaciones heurísticas sobre el mismo cliente vulnerar con facilidad. Esto plantea el desafío de que los indicadores en los que se basa declaran el estado legítimo del dispositivo se pueden haber falsificado. Esta guía ofrece garantías criptográficas respaldadas por hardware del la identidad del dispositivo y que su estado no se modificó y cumple con las políticas al inicio; llamado Acceso verificado.

Público principal Administradores de dominios de TI empresariales
Componentes técnicos ChromeOS, API de Google Verified Access

Requisitos para el acceso verificado

Completa la siguiente configuración antes de implementar el proceso de acceso verificado.

Habilita la API

Configura un proyecto de la Consola de APIs de Google y habilita la API:

  1. Crea o usa un proyecto existente en la Consola de APIs de Google.
  2. Ve a la sección APIs habilitadas y de Google Cloud.
  3. Habilita la API de Chrome Verified Access.
  4. Crea una clave de API para tu aplicación. Para ello, sigue las indicaciones que se brindan en la documentación de la API de Google Cloud.

Crea una cuenta de servicio

Para que el servicio de red acceda a la API de Chrome Verified Access para verificar tu desafío-respuesta, crea una cuenta de servicio y una clave de cuenta de servicio (no necesitas crear un nuevo proyecto de Cloud, puedes usar el mismo).

Una vez que crees la clave de la cuenta de servicio, deberías tener una cuenta de servicio archivo de clave privada descargado. Esta es la única copia de la clave privada, así que asegúrate de almacenarlo de forma segura.

Inscribe un dispositivo Chromebook administrado

Necesitas una configuración de dispositivo Chromebook administrada correctamente con tu Chrome extensión de Acceso verificado.

  1. La Chromebook debe estar inscrita para la administración empresarial o educativa.
  2. El usuario del dispositivo debe ser un usuario registrado del mismo dominio.
  3. La extensión de Chrome para Acceso verificado debe estar instalada en el dispositivo.
  4. Las políticas están configuradas para habilitar el acceso verificado. Incluye Chrome en la lista de entidades permitidas y otorga acceso a la API a la cuenta de servicio que representa el servicio de red (consulta la documentación de ayuda de la Consola del administrador de Google).

Verifica el usuario y el dispositivo

Los desarrolladores pueden usar el Acceso verificado para la verificación de usuarios o dispositivos, o bien usar ambos para la seguridad adicional:

  • Verificación del dispositivo: Si se realiza correctamente, la verificación del dispositivo proporciona un garantizar que el dispositivo Chrome esté inscrito en un dominio administrado y que cumple con la política de dispositivo del modo de inicio verificado que especifica el dominio administrador. Si el servicio de red recibe permiso para ver el dispositivo (consulta la documentación de ayuda de la Consola del administrador de Google) y, luego, también recibirá un Es el ID de dispositivo que se puede usar para realizar auditorías, hacer un seguimiento o llamar a la API de Directory.

  • Verificación del usuario: Si se realiza correctamente, la verificación del usuario garantiza. que un usuario de Chrome que accedió es un usuario administrado, utiliza un dispositivo inscrito y cumple con la política de usuario del modo de inicio verificado que especifica el dominio administrador. Si el servicio de red tiene permiso para recibir datos adicionales del usuario, también obtendrá una solicitud de firma de certificado emitida por el usuario (CSR en la forma de clave pública firmada y desafío, o SPKAC, también conocido como formato keygen).

Cómo verificar el usuario y el dispositivo

  1. Obtener un desafío: La extensión de Chrome del dispositivo se comunica con el equipo de Verificado. Acceder a la API para obtener un desafío. El desafío son los datos opacos (un BLOB firmado por Google) que es de 1 minuto, es decir, La verificación de desafío-respuesta (paso 3) falla si se utiliza un desafío inactivo.

    En el caso de uso más sencillo, el usuario inicia este flujo haciendo clic en un botón que que genera la extensión (esto también es lo que proporciona la extensión hace).

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

    Código de ayuda para codificar el desafío: Si usas la v1 de la API, el desafío tendrá que codificarse.

    // 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. Generar una respuesta de desafío: La extensión de Chrome usa el desafío que recibido en el paso 1 para llamar a la API de Chrome enterprise.platformKeys. Esta genera una respuesta de desafío firmada y encriptada, y la extensión incluye en la solicitud de acceso que envía al servicio de red.

    En este paso, no hay intento de definir un protocolo que la extensión y usar el servicio de red para la comunicación. Ambas entidades se implementan no se indica cómo se comunican entre sí. Los ejemplo sería enviar una respuesta de desafío (codificada como URL) como una cadena de consulta con HTTP POST o un encabezado HTTP especial.

    Este es un código de muestra para generar una respuesta de desafío:

    Genera una respuesta de desafío

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

    Función de devolución de llamada de desafío

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

    Código de ayuda para la conversión de 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. Verificar la respuesta al desafío: Al recibir una respuesta al desafío de un dispositivo (quizás como una extensión de un protocolo de autenticación existente), el servicio de red debe llamar a la API de Verified Access para verificar el dispositivo identidad y postura de políticas (consulta el código de ejemplo a continuación). Para combatir la falsificación de identidad, recomendar que el servicio de red identifique al cliente con el que se está comunicando Incluye la identidad esperada del cliente en su solicitud:

    • Para la verificación de dispositivos, se debe proporcionar el dominio esperado del dispositivo. de Google Cloud. Es probable que sea un valor hard-coded en muchos casos, ya que la red protege los recursos de un dominio en particular. Si no se sabe con anticipación, se puede inferir de la identidad del usuario.
    • Para la verificación del usuario, la dirección de correo electrónico del usuario esperado debe ser que se proporcionan. Esperamos que el servicio de red conozca a sus usuarios (normalmente, requieren que los usuarios accedan).

    Cuando se llama a la API de Google, esta realiza una serie de comprobaciones, como las siguientes:

    • Verifica que ChromeOS produzca la respuesta de desafío y que no modificada en tránsito
    • Verifica que el dispositivo o el usuario estén administrados por una empresa.
    • Verifica que la identidad del dispositivo o usuario coincida con la identidad (si se proporciona esta última).
    • Verificar que el desafío al que se está respondiendo sea recientes (no más de 1 minuto de antigüedad)
    • Verifica que el dispositivo o el usuario cumpla con la política especificada por el administrador de dominio.
    • Verifica que el emisor (servicio de red) tenga permiso para llamar la API.
    • Si al emisor se le otorga permiso para obtener un dispositivo adicional o datos del usuario, como el ID de dispositivo o la firma del certificado del usuario de respuesta ante incidentes (CSR) en la respuesta.

    En este ejemplo, se usa la biblioteca de 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. Otorga acceso: Este paso también es específico del servicio de red. Este es un implementación sugerida (no prescrita). Estas son algunas de las acciones posibles:

    • Creación de una cookie de sesión
    • Emitir un certificado para un usuario o dispositivo En caso de que un usuario la verificación y suponiendo que el servicio de red tiene acceso datos adicionales del usuario (mediante la política de la Consola del administrador de Google), recibe una CSR firmada por el usuario, que luego puede usarse para obtener certificado de la autoridad certificadora. Cuando realices la integración con MicrosoftR CA, el servicio de red puede actuar como intermediario y utilizar la interfaz ICertRequest.

Cómo usar certificados de cliente con el acceso verificado

Cómo utilizar certificados de cliente con el Acceso verificado.

En una organización grande, puede haber varios servicios de red (servidores VPN, puntos de acceso Wi-Fi, firewalls y varios sitios de intranet) que se beneficiarían del acceso verificado. Sin embargo, compilar la lógica de los pasos 2 a 4 (en la sección anterior) de cada uno de estos servicios de red, es posible que no se práctico. A menudo, muchos de estos servicios de red ya tienen la capacidad requieren certificados de cliente como parte de sus autenticaciones (por ejemplo, EAP-TLS o páginas de intranet de TLS mutua). Entonces, si el certificado de Enterprise La autoridad que emite estos certificados de cliente podría implementar los pasos 2 a 4. condicional la emisión del certificado de cliente en la respuesta de desafío verificación, la posesión del certificado podría ser la prueba de que el cliente es genuino y cumple con la política corporativa. Luego, cada red Wi-Fi punto de acceso, servidor de VPN, etc., podrían verificar en lugar de seguir los pasos 2 a 4.

En otras palabras, aquí la AC (que emite el certificado de cliente a la ) toma la función del servicio de red en la Figura 1. Necesita invocar la API de Verified Access y, únicamente tras la verificación de respuesta de comprobación aprueba, proporciona el certificado al cliente. Proporcionar el certificado a el cliente es el equivalente del paso 4, Otorga acceso en la Figura 1.

El proceso para enviar certificados de cliente de forma segura a las Chromebooks se describe consulta este artículo. Si el botón se sigue el diseño descrito en este párrafo, luego, Verified Access Extension y la extensión de incorporación del certificado de cliente. Más información sobre cómo escribir una extensión de integración de certificado de cliente.