Como usar a API Update

Visão geral

A API Update permite que seus aplicativos cliente façam o download de versões com hash das listas da Web Risk para armazenamento em um banco de dados local ou na memória. Os URLs podem ser verificados localmente. Quando uma correspondência é encontrada no banco de dados local, o cliente envia uma solicitação aos servidores da Web Risk para verificar se o URL está incluído nas listas da Web Risk.

Como atualizar o banco de dados local

Para se manter atualizado, os clientes precisam atualizar periodicamente as listas da Web Risk no banco de dados local. Para economizar largura de banda, os clientes fazem o download dos prefixos de hash dos URLs em vez dos URLs brutos. Por exemplo, se "www.badurl.com/" estiver em uma lista da Web Risk, os clientes farão o download do prefixo hash SHA256 desse URL em vez do próprio URL. Na maioria dos casos, os prefixos de hash têm 4 bytes, o que significa que o custo médio da largura de banda de download de uma única entrada de lista é 4 bytes antes da compactação.

Para atualizar as listas da Web Risk no banco de dados local, envie uma solicitação HTTP GET para o método threatLists.computeDiff:

  • A solicitação HTTP GET inclui o nome da lista a ser atualizada junto com as restrições do cliente para considerar as limitações de memória e largura de banda.
  • A resposta HTTP GET retorna uma atualização completa ou parcial. A resposta também pode retornar um tempo de espera recomendado até a próxima operação de diferença de computação.

Exemplo: threatLists.computeDiff

Solicitação GET HTTP

No exemplo a seguir, as diferenças da lista da Web Risk do MALWARE são solicitadas. Para mais detalhes, consulte os parâmetros de consulta threatLists.computeDiff e as explicações que seguem o exemplo de código.

Método HTTP e URL:

GET https://webrisk.googleapis.com/v1/threatLists:computeDiff?threatType=MALWARE&versionToken=Gg4IBBADIgYQgBAiAQEoAQ%3D%3D&constraints.maxDiffEntries=2048&constraints.maxDatabaseEntries=4096&constraints.supportedCompressions=RAW&key=API_KEY

Para enviar a solicitação, escolha uma destas opções:

curl

Execute o seguinte comando:

curl -X GET \
"https://webrisk.googleapis.com/v1/threatLists:computeDiff?threatType=MALWARE&versionToken=Gg4IBBADIgYQgBAiAQEoAQ%3D%3D&constraints.maxDiffEntries=2048&constraints.maxDatabaseEntries=4096&constraints.supportedCompressions=RAW&key=API_KEY"

PowerShell

Execute o seguinte comando:

$headers = @{  }

Invoke-WebRequest `
-Method GET `
-Headers $headers `
-Uri "https://webrisk.googleapis.com/v1/threatLists:computeDiff?threatType=MALWARE&versionToken=Gg4IBBADIgYQgBAiAQEoAQ%3D%3D&constraints.maxDiffEntries=2048&constraints.maxDatabaseEntries=4096&constraints.supportedCompressions=RAW&key=API_KEY" | Select-Object -Expand Content

Você receberá uma resposta JSON semelhante a esta:

{
  "recommendedNextDiff": "2020-01-08T19:41:45.436722194Z",
  "responseType": "RESET",
  "additions": {
    "rawHashes": [
      {
        "prefixSize": 4,
        "rawHashes": "AArQMQAMoUgAPn8lAE..."
      }
    ]
  },
  "newVersionToken": "ChAIARAGGAEiAzAwMSiAEDABEPDyBhoCGAlTcIVL",
  "checksum": {
    "sha256": "wy6jh0+MAg/V/+VdErFhZIpOW+L8ulrVwhlV61XkROI="
  }
}

Java


import com.google.cloud.webrisk.v1.WebRiskServiceClient;
import com.google.protobuf.ByteString;
import com.google.webrisk.v1.CompressionType;
import com.google.webrisk.v1.ComputeThreatListDiffRequest;
import com.google.webrisk.v1.ComputeThreatListDiffRequest.Constraints;
import com.google.webrisk.v1.ComputeThreatListDiffResponse;
import com.google.webrisk.v1.ThreatType;
import java.io.IOException;

public class ComputeThreatListDiff {

  public static void main(String[] args) throws IOException {
    // TODO(developer): Replace these variables before running the sample.
    // The threat list to update. Only a single ThreatType should be specified per request.
    ThreatType threatType = ThreatType.MALWARE;

    // The current version token of the client for the requested list. If the client does not have
    // a version token (this is the first time calling ComputeThreatListDiff), this may be
    // left empty and a full database snapshot will be returned.
    ByteString versionToken = ByteString.EMPTY;

    // The maximum size in number of entries. The diff will not contain more entries
    // than this value. This should be a power of 2 between 2**10 and 2**20.
    // If zero, no diff size limit is set.
    int maxDiffEntries = 1024;

    // Sets the maximum number of entries that the client is willing to have in the local database.
    // This should be a power of 2 between 2**10 and 2**20. If zero, no database size limit is set.
    int maxDatabaseEntries = 1024;

    // The compression type supported by the client.
    CompressionType compressionType = CompressionType.RAW;

    computeThreatDiffList(threatType, versionToken, maxDiffEntries, maxDatabaseEntries,
        compressionType);
  }

  // Gets the most recent threat list diffs. These diffs should be applied to a local database of
  // hashes to keep it up-to-date.
  // If the local database is empty or excessively out-of-date,
  // a complete snapshot of the database will be returned. This Method only updates a
  // single ThreatList at a time. To update multiple ThreatList databases, this method needs to be
  // called once for each list.
  public static void computeThreatDiffList(ThreatType threatType, ByteString versionToken,
      int maxDiffEntries, int maxDatabaseEntries, CompressionType compressionType)
      throws IOException {
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests. After completing all of your requests, call
    // the `webRiskServiceClient.close()` method on the client to safely
    // clean up any remaining background resources.
    try (WebRiskServiceClient webRiskServiceClient = WebRiskServiceClient.create()) {

      Constraints constraints = Constraints.newBuilder()
          .setMaxDiffEntries(maxDiffEntries)
          .setMaxDatabaseEntries(maxDatabaseEntries)
          .addSupportedCompressions(compressionType)
          .build();

      ComputeThreatListDiffResponse response = webRiskServiceClient.computeThreatListDiff(
          ComputeThreatListDiffRequest.newBuilder()
              .setThreatType(threatType)
              .setVersionToken(versionToken)
              .setConstraints(constraints)
              .build());

      // The returned response contains the following information:
      // https://cloud.google.com/web-risk/docs/reference/rpc/google.cloud.webrisk.v1#computethreatlistdiffresponse
      // Type of response: DIFF/ RESET/ RESPONSE_TYPE_UNSPECIFIED
      System.out.println(response.getResponseType());
      // List of entries to add and/or remove.
      // System.out.println(response.getAdditions());
      // System.out.println(response.getRemovals());

      // New version token to be used the next time when querying.
      System.out.println(response.getNewVersionToken());

      // Recommended next diff timestamp.
      System.out.println(response.getRecommendedNextDiff());

      System.out.println("Obtained threat list diff.");
    }
  }
}

Python

from google.cloud import webrisk_v1
from google.cloud.webrisk_v1 import ComputeThreatListDiffResponse


def compute_threatlist_diff(
    threat_type: webrisk_v1.ThreatType,
    version_token: bytes,
    max_diff_entries: int,
    max_database_entries: int,
    compression_type: webrisk_v1.CompressionType,
) -> ComputeThreatListDiffResponse:
    """Gets the most recent threat list diffs.

    These diffs should be applied to a local database of hashes to keep it up-to-date.
    If the local database is empty or excessively out-of-date,
    a complete snapshot of the database will be returned. This Method only updates a
    single ThreatList at a time. To update multiple ThreatList databases, this method needs to be
    called once for each list.

    Args:
        threat_type: The threat list to update. Only a single ThreatType should be specified per request.
            threat_type = webrisk_v1.ThreatType.MALWARE

        version_token: The current version token of the client for the requested list. If the
            client does not have a version token (this is the first time calling ComputeThreatListDiff),
            this may be left empty and a full database snapshot will be returned.

        max_diff_entries: The maximum size in number of entries. The diff will not contain more entries
            than this value. This should be a power of 2 between 2**10 and 2**20.
            If zero, no diff size limit is set.
            max_diff_entries = 1024

        max_database_entries: Sets the maximum number of entries that the client is willing to have in the local database.
            This should be a power of 2 between 2**10 and 2**20. If zero, no database size limit is set.
            max_database_entries = 1024

        compression_type: The compression type supported by the client.
            compression_type = webrisk_v1.CompressionType.RAW

    Returns:
        The response which contains the diff between local and remote threat lists. In addition to the threat list,
        the response also contains the version token and the recommended time for next diff.
    """

    webrisk_client = webrisk_v1.WebRiskServiceClient()

    constraints = webrisk_v1.ComputeThreatListDiffRequest.Constraints()
    constraints.max_diff_entries = max_diff_entries
    constraints.max_database_entries = max_database_entries
    constraints.supported_compressions = [compression_type]

    request = webrisk_v1.ComputeThreatListDiffRequest()
    request.threat_type = threat_type
    request.version_token = version_token
    request.constraints = constraints

    response = webrisk_client.compute_threat_list_diff(request)

    # The returned response contains the following information:
    # https://cloud.google.com/web-risk/docs/reference/rpc/google.cloud.webrisk.v1#computethreatlistdiffresponse
    # Type of response: DIFF/ RESET/ RESPONSE_TYPE_UNSPECIFIED
    print(response.response_type)
    # New version token to be used the next time when querying.
    print(response.new_version_token)
    # Recommended next diff timestamp.
    print(response.recommended_next_diff)

    return response

Listas da Web Risk

O campo threatType identifica a lista da Web Risk. No exemplo, as diferenças para a lista da Web Risk do MALWARE são solicitadas.

Token de versão

O campo versionToken contém o estado atual do cliente da lista da Web Risk. Os tokens de versão são retornados no campo newVersionToken da resposta threatLists.computeDiff. Para atualizações iniciais, deixe o campo versionToken vazio.

Restrições de tamanho

O campo maxDiffEntries especifica o número total de atualizações que o cliente pode gerenciar (no exemplo, 2048). O campo maxDatabaseEntries especifica o número total de entradas que o banco de dados local pode gerenciar (no exemplo, 4096). Os clientes precisam definir restrições de tamanho para proteger a memória e as limitações de largura de banda e evitar o crescimento da lista. Para mais informações, consulte Atualizar restrições.

Compactação compatível

O campo supportedCompressions lista os tipos de compactação compatíveis com o cliente. No exemplo, o cliente suporta apenas dados brutos e não compactados. No entanto, a Web Risk é compatível com outros tipos de compactação. Para mais informações, consulte Compactação.

Resposta HTTP GET

Neste exemplo, a resposta retorna uma atualização parcial da lista da Web Risk usando o tipo de compactação solicitado.

Corpo da resposta

O corpo da resposta inclui as informações de diferenças (o tipo de resposta, as adições e remoções a serem aplicadas ao banco de dados local, o novo token de versão e uma soma de verificação).

No exemplo, a resposta também inclui um próximo horário de diferença recomendado. Para mais detalhes, consulte o corpo da resposta threatLists.computeDiff e as explicações que seguem o exemplo de código.

{
  "responseType" :   "DIFF",
  "recommendedNextDiff": "2019-12-31T23:59:59.000000000Z",
  "additions": {
    "compressionType": "RAW",
    "rawHashes": [{
      "prefixSize": 4,
      "rawHashes":  "rnGLoQ=="
    }]
  },
  "removals": {
    "rawIndices": {
      "indices": [0, 2, 4]
    }
  },
  "newVersionToken": "ChAIBRADGAEiAzAwMSiAEDABEAFGpqhd",
  "checksum": {
    "sha256": "YSgoRtsRlgHDqDA3LAhM1gegEpEzs1TjzU33vqsR8iM="
  },
  "recommendedNextDiff": "2019-07-17T15:01:23.045123456Z"
}

Diferenças de banco de dados

O campo responseType indicará uma atualização parcial (DIFF) ou completa (RESET). No exemplo, as diferenças parciais são retornadas. Portanto, a resposta inclui adições e remoções. Pode haver vários conjuntos de adições, mas apenas um conjunto de remoções. Para mais informações, consulte Diferenças de banco de dados.

Novo token de versão

O campo newVersionToken contém o novo token de versão da lista da Web Risk recém-atualizada. Os clientes precisam salvar o novo estado do cliente para solicitações de atualização subsequentes (o campo versionToken na solicitação threatLists.computeDiff.

Somas de verificação

A soma de verificação permite que os clientes verifiquem se o banco de dados local não foi corrompido. Se a soma de verificação não corresponder, o cliente precisará limpar o banco de dados e reemitir uma atualização com um campo versionToken vazio. No entanto, os clientes nessa situação ainda precisam seguir os intervalos de tempo para atualizações. Para mais informações, consulte Frequência de solicitação.

O campo recommendedNextDiff indica um carimbo de data / hora até quando o cliente deve aguardar antes de enviar outra solicitação de atualização. O período de espera recomendado pode ou não ser incluído na resposta. Para mais detalhes, consulte Frequência de solicitação.

Como verificar URLs

Para verificar se um URL está em uma lista da Web Risk, primeiro o cliente precisa calcular o hash e o prefixo de hash do URL. Para detalhes, consulte URLs e hash. Em seguida, o cliente consulta o banco de dados local para determinar se há uma correspondência. Se o prefixo de hash não estiver presente no banco de dados local, o URL será considerado seguro (ou seja, não nas listas da Web Risk).

Se o prefixo de hash estiver presente no banco de dados local (uma colisão de prefixo de hash), o cliente precisará enviar o prefixo de hash aos servidores da Web Risk para verificação. Os servidores retornarão todos os hashes SHA 256 completos que contêm o prefixo de hash fornecido. Se um desses hashes completos corresponder ao hash completo do URL em questão, o URL será considerado não seguro. Se nenhum dos hashes completos corresponder ao hash completo do URL em questão, esse URL será considerado seguro.

Em nenhum momento o Google aprende sobre os URLs que você está examinando. O Google aprende os prefixos de hash dos URLs, mas os prefixos de hash não fornecem muitas informações sobre os URLs reais.

Para verificar se um URL está em uma lista da Web Risk, envie uma solicitação HTTP GET para o método hashes.search:

  • A solicitação HTTP GET inclui o prefixo de hash do URL a ser verificado.
  • A resposta HTTP GET retorna os hashes de comprimento total correspondentes, juntamente com os tempos de expiração positivos e negativos.

Exemplo: hashes.search

Solicitação GET HTTP

No exemplo a seguir, os nomes de duas listas da Web Risk e um prefixo de hash são enviados para comparação e verificação. Para mais detalhes, consulte os parâmetros de consulta hashes.search e as explicações que seguem o exemplo de código.

curl \
  -H "Content-Type: application/json" \
  "https://webrisk.googleapis.com/v1/hashes:search?key=YOUR_API_KEY&threatTypes=MALWARE&threatTypes=SOCIAL_ENGINEERING&hashPrefix=WwuJdQ%3D%3D"

Java


import com.google.cloud.webrisk.v1.WebRiskServiceClient;
import com.google.protobuf.ByteString;
import com.google.webrisk.v1.SearchHashesRequest;
import com.google.webrisk.v1.SearchHashesResponse;
import com.google.webrisk.v1.SearchHashesResponse.ThreatHash;
import com.google.webrisk.v1.ThreatType;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;

public class SearchHashes {

  public static void main(String[] args) throws IOException, NoSuchAlgorithmException {
    // TODO(developer): Replace these variables before running the sample.
    // A hash prefix, consisting of the most significant 4-32 bytes of a SHA256 hash.
    // For JSON requests, this field is base64-encoded. Note that if this parameter is provided
    // by a URI, it must be encoded using the web safe base64 variant (RFC 4648).
    String uri = "http://example.com";
    String encodedUri = Base64.getUrlEncoder().encodeToString(uri.getBytes(StandardCharsets.UTF_8));
    MessageDigest digest = MessageDigest.getInstance("SHA-256");
    byte[] encodedHashPrefix = digest.digest(encodedUri.getBytes(StandardCharsets.UTF_8));

    // The ThreatLists to search in. Multiple ThreatLists may be specified.
    // For the list on threat types, see: https://cloud.google.com/web-risk/docs/reference/rpc/google.cloud.webrisk.v1#threattype
    List<ThreatType> threatTypes = Arrays.asList(ThreatType.MALWARE, ThreatType.SOCIAL_ENGINEERING);

    searchHash(ByteString.copyFrom(encodedHashPrefix), threatTypes);
  }

  // Gets the full hashes that match the requested hash prefix.
  // This is used after a hash prefix is looked up in a threatList and there is a match.
  // The client side threatList only holds partial hashes so the client must query this method
  // to determine if there is a full hash match of a threat.
  public static void searchHash(ByteString encodedHashPrefix, List<ThreatType> threatTypes)
      throws IOException {
    // Initialize client that will be used to send requests. This client only needs to be created
    // once, and can be reused for multiple requests. After completing all of your requests, call
    // the `webRiskServiceClient.close()` method on the client to safely
    // clean up any remaining background resources.
    try (WebRiskServiceClient webRiskServiceClient = WebRiskServiceClient.create()) {

      // Set the hashPrefix and the threat types to search in.
      SearchHashesResponse response = webRiskServiceClient.searchHashes(
          SearchHashesRequest.newBuilder()
              .setHashPrefix(encodedHashPrefix)
              .addAllThreatTypes(threatTypes)
              .build());

      // Get all the hashes that match the prefix. Cache the returned hashes until the time
      // specified in threatHash.getExpireTime()
      // For more information on response type, see: https://cloud.google.com/web-risk/docs/reference/rpc/google.cloud.webrisk.v1#threathash
      for (ThreatHash threatHash : response.getThreatsList()) {
        System.out.println(threatHash.getHash());
      }
      System.out.println("Completed searching threat hashes.");
    }
  }
}

Python

from google.cloud import webrisk_v1


def search_hashes(hash_prefix: bytes, threat_type: webrisk_v1.ThreatType) -> list:
    """Gets the full hashes that match the requested hash prefix.

    This is used after a hash prefix is looked up in a threatList and there is a match.
    The client side threatList only holds partial hashes so the client must query this method
    to determine if there is a full hash match of a threat.

    Args:
        hash_prefix: A hash prefix, consisting of the most significant 4-32 bytes of a SHA256 hash.
            For JSON requests, this field is base64-encoded. Note that if this parameter is provided
            by a URI, it must be encoded using the web safe base64 variant (RFC 4648).
            Example:
                uri = "http://example.com"
                sha256 = sha256()
                sha256.update(base64.urlsafe_b64encode(bytes(uri, "utf-8")))
                hex_string = sha256.digest()

        threat_type: The ThreatLists to search in. Multiple ThreatLists may be specified.
            For the list on threat types, see:
            https://cloud.google.com/web-risk/docs/reference/rpc/google.cloud.webrisk.v1#threattype
            threat_type = [webrisk_v1.ThreatType.MALWARE, webrisk_v1.ThreatType.SOCIAL_ENGINEERING]

    Returns:
        A hash list that contain all hashes that matches the given hash prefix.
    """
    webrisk_client = webrisk_v1.WebRiskServiceClient()

    # Set the hashPrefix and the threat types to search in.
    request = webrisk_v1.SearchHashesRequest()
    request.hash_prefix = hash_prefix
    request.threat_types = [threat_type]

    response = webrisk_client.search_hashes(request)

    # Get all the hashes that match the prefix. Cache the returned hashes until the time
    # specified in threat_hash.expire_time
    # For more information on response type, see:
    # https://cloud.google.com/web-risk/docs/reference/rpc/google.cloud.webrisk.v1#threathash
    hash_list = []
    for threat_hash in response.threats:
        hash_list.append(threat_hash.hash)
    return hash_list

Listas da Web Risk

O campo threatTypes identifica as listas da Web Risk. No exemplo, duas listas são identificadas: MALWARE e SOCIAL_ENGINEERING.

Prefixos de hash de ameaças

O campo hashPrefix contém o prefixo de hash do URL que você quer verificar. Esse campo precisa conter o prefixo de hash exato que está presente no banco de dados local. Por exemplo, se o prefixo de hash local tiver 4 bytes, o campo hashPrefix precisará ter 4 bytes. Se o prefixo de hash local tiver sido aumentado para 7 bytes, o campo hashPrefix precisará ter 7 bytes.

Resposta HTTP GET

No exemplo a seguir, a resposta retorna as ameaças correspondentes, contendo as listas da Web Risk correspondentes e os tempos de expiração.

Corpo da resposta

O corpo da resposta inclui as informações de correspondência (os nomes da lista e os hashes de comprimento total e as durações do cache). Para mais detalhes, consulte o corpo da resposta hashes.search e as explicações que seguem o exemplo de código.

{
  "threats": [{
      "threatTypes": ["MALWARE"],
      "hash": "WwuJdQx48jP-4lxr4y2Sj82AWoxUVcIRDSk1PC9Rf-4="
      "expireTime": "2019-07-17T15:01:23.045123456Z"
    }, {
      "threatTypes": ["MALWARE", "SOCIAL_ENGINEERING"],
      "hash": "WwuJdQxaCSH453-uytERC456gf45rFExcE23F7-hnfD="
      "expireTime": "2019-07-17T15:01:23.045123456Z"
    },
  }],
  "negativeExpireTime": "2019-07-17T15:01:23.045123456Z"
}

Correspondências

O campo threats retorna um hash completo correspondente ao prefixo de hash. Os URLs correspondentes a esses hashes são considerados não seguros. Se nenhuma correspondência for encontrada para um prefixo de hash, nada será retornado. o URL correspondente a esse prefixo de hash é considerado seguro.

Tempo de expiração

Os campos expireTime e negativeExpireTime indicam até quando os hashes precisam ser considerados não seguros ou seguros, respectivamente. Para mais detalhes, consulte Armazenamento em cache.