Sobre este guia
A API Chrome Verified Access permite serviços de rede, como VPNs, intranet páginas, e assim por diante, para verificar criptograficamente se seus clientes são genuínos e estão em conformidade com a política corporativa. A maioria das grandes empresas precisa permitir que apenas dispositivos gerenciados pela empresa acessem as redes WPA2 EAP-TLS, acesso de nível superior em VPNs e páginas de intranet de TLS mútuo. Muitos soluções dependem de verificações heurísticas do mesmo cliente, que podem ter sido comprometido. Isso apresenta o desafio em que os sinais confiáveis atestem o status legítimo do dispositivo podem ter sido falsificado. Este guia oferece garantias criptográficas com suporte de hardware da identidade do dispositivo e que o estado dele não foi modificado e está em conformidade com a política na inicialização. chamada "Acesso verificado".
Público principal | Administradores de domínios de TI corporativos |
Componentes técnicos | ChromeOS, API Google Verified Access |
Pré-requisitos do "Acesso verificado"
Conclua a configuração a seguir antes de implementar o processo de "Acesso verificado".
Ativar a API
Configure um projeto do Console de APIs do Google e ative a API:
- Crie ou use um projeto existente no Console de APIs do Google.
- Acesse o APIs ativadas e de serviço.
- Ative a API Chrome Verified Access.
- Crie uma chave de API para o aplicativo seguindo a documentação da API Google Cloud.
Criar uma conta de serviço
Para que o serviço de rede acesse a API Verified Access do Chrome para verificar seu resposta ao desafio, Criar uma conta de serviço e uma chave de conta de serviço Não é necessário criar um novo projeto do Cloud, mas é possível que você use o mesmo projeto.
Depois de criar a chave da conta de serviço, você terá uma conta de serviço o download do arquivo de chave privada. Essa é a única cópia da chave privada, portanto, você deve armazená-lo com segurança.
Registrar um dispositivo Chromebook gerenciado
É preciso ter um dispositivo Chromebook gerenciado corretamente com o Chrome para "Acesso verificado".
- O dispositivo Chromebook precisa estar registrado para o gerenciamento empresarial ou educacional.
- O usuário do dispositivo precisa ser um usuário registrado no mesmo domínio.
- A extensão do Chrome para "Acesso verificado" precisa estar instalada no dispositivo.
- As políticas são configuradas para ativar o "Acesso verificado" e permitir o acesso do Chrome de serviço e conceda acesso à API para a conta de serviço que representa serviço de rede (consulte a Documentação de ajuda do Google Admin Console).
Verificar usuário e dispositivo
Os desenvolvedores podem usar o "Acesso verificado" para verificação de usuários ou dispositivos ou ambos para aumentar a segurança:
Verificação do dispositivo: se for bem-sucedida, a verificação do dispositivo fornecerá uma garantir que o dispositivo Chrome esteja registrado em um domínio gerenciado e que ele obedece à política do dispositivo no modo de inicialização verificada, conforme especificado pelo domínio administrador. Se o serviço de rede tiver permissão para ver o dispositivo identidade (consulte a documentação de ajuda do Google Admin Console), ele também recebe um ID do dispositivo, que pode ser usado para auditoria, acompanhamento ou chamada da API Directory.
Verificação do usuário: se a verificação for concluída, a verificação do usuário vai fornecer uma garantia. que um usuário conectado do Chrome é um usuário gerenciado, está usando um dispositivo registrado e obedece à política do usuário do modo de inicialização verificada, conforme especificado pelo domínio administrador. Se o serviço de rede tiver permissão para receber dados adicionais do usuário, ele também recebe uma solicitação de assinatura de certificado pelo usuário (CSR na forma de chave pública-e-desafio assinada, ou SPKAC, também conhecido como formato keygen).
Como verificar o usuário e o dispositivo
Receber um desafio: a extensão do Chrome no dispositivo entra em contato com o Access API para receber um desafio. O desafio é um conjunto de dados (um blob assinado pelo Google) com duração de 1 minuto, ou seja, a verificação de resposta/desafio (etapa 3) falhará se um desafio obsoleto for usado.
No caso de uso mais simples, o usuário inicia esse fluxo clicando em um botão que gerada pela extensão (é isso que a extensão de exemplo fornecida pelo Google tem).
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 auxiliar para codificar o desafio: se você estiver usando a v1 da API, os desafio terá de ser codificado.
// 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); } };
Gerar uma resposta do desafio: a extensão do Chrome usa o desafio. recebidas na etapa 1 para chamar a API enterprise.platformKeys do Chrome. Isso gera uma resposta do desafio assinada e criptografada, que a extensão inclui na solicitação de acesso que envia ao serviço de rede.
Nesta etapa, não há tentativa de definir um protocolo que a extensão e e serviços de rede para comunicação. Ambas as entidades são implementadas por desenvolvedores externos e não há regras de como eles se comunicam. Um exemplo seria enviar uma resposta de desafio (codificada para URL) como uma string de consulta , usando POST HTTP ou um cabeçalho HTTP especial.
Este é um exemplo de código para gerar uma resposta do desafio:
Gerar resposta ao desafio
// 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); }
Função de callback do desafio
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 auxiliar para conversão do 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; }
Verificar a resposta do desafio: ao receber a resposta do desafio de um dispositivo (talvez como uma extensão de um protocolo de autenticação existente), o serviço de rede precisa chamar a API Verified Access para verificar o dispositivo identidade e postura de política (veja o código de exemplo abaixo). Para combater a falsificação, recomendamos que o serviço de rede identifique o cliente com quem está se comunicando inclua a identidade esperada do cliente na solicitação:
- Para a verificação do dispositivo, informe o domínio do dispositivo esperado. , Em muitos casos, esse é um valor codificado, porque a rede protege os recursos de um determinado domínio. Se você não souber com antecedência, ela pode ser inferida a partir da identidade do usuário.
- Para a verificação do usuário, use o endereço de e-mail esperado. fornecidas. Esperamos que o serviço de rede conheça seus usuários (normalmente ele exigiria que os usuários fizessem login).
Quando a API do Google é chamada, ela realiza várias verificações, como:
- Verificar se a resposta do desafio é produzida pelo ChromeOS e não é modificado em trânsito
- Verifique se o dispositivo ou usuário é gerenciado por uma empresa.
- Verifique se a identidade do dispositivo/usuário corresponde ao identidade (se a segunda for fornecida).
- Verificar se o desafio respondido é recentes (no máximo 1 minuto).
- Verifique se o dispositivo ou usuário está em conformidade com a política conforme especificado por o administrador do domínio.
- Verificar se o autor da chamada (serviço de rede) tem permissão para chamar a API.
- Se o autor da chamada tiver permissão para obter dispositivos ou dados do usuário, inclua o ID do dispositivo ou a assinatura de certificado (CSR) na resposta.
Este exemplo usa a biblioteca 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(); }
Conceder acesso: esta etapa também é específica para o serviço de rede. Esta é uma uma implementação sugerida (não prescrita). Estas são as possíveis ações:
- Criação de um cookie de sessão
- Emitir um certificado para o usuário ou dispositivo. Em caso de êxito do usuário e presumindo que o serviço de rede tenha recebido acesso a dados adicionais do usuário (pela política do Google Admin Console), recebe uma CSR assinada por usuário, que pode então ser usada para obter a solicitação real certificado da autoridade certificadora. Ao integrar com MicrosoftR CA, o serviço de rede pode atuar um intermediário e usar a interface ICertRequest.
Como usar certificados do cliente com Acesso verificado
Em uma grande organização, pode haver vários serviços de rede (servidores VPN, pontos de acesso Wi-Fi, firewalls e vários sites da intranet) que com o recurso "Acesso verificado". No entanto, criar a lógica das etapas 2 a 4 (na seção acima) em cada um desses serviços de rede podem não ser práticos. Muitas vezes, muitos desses serviços de rede já têm a capacidade de exigir certificados do cliente como parte das autenticações (por exemplo, EAP-TLS ou páginas de intranet de TLS mútuo). Portanto, se o certificado empresarial A autoridade que emite esses certificados do cliente pode implementar as etapas de 2 a 4 e condição para a emissão do certificado do cliente no desafio/resposta verificação, a posse do certificado pode ser a prova de que o cliente é verdadeiro e está em conformidade com a política corporativa. Depois disso, cada rede Wi-Fi ponto de acesso, servidor VPN e assim por diante poderiam verificar este certificado do cliente em vez de seguir as etapas de 2 a 4.
Em outras palavras, aqui é a CA (que emite o certificado do cliente para a ) assume o papel do Serviço de rede na Figura 1. Ele precisa invocar a API Verified Access e somente após a verificação da resposta ao desafio forneça o certificado ao cliente. Fornecer o certificado para o cliente é o equivalente à Etapa 4: conceder acesso na figura 1.
O processo de obtenção de certificados do cliente nos Chromebooks é descrito neste artigo. Se o o design descrito neste parágrafo é seguido, depois a Extensão de acesso verificado e a extensão de integração de certificado do cliente podem ser combinadas em um só. Saiba mais sobre como criar uma extensão de integração de certificado do cliente.