Usar la API Update

Información general

La API Update permite a tus aplicaciones cliente descargar versiones hash de las listas de riesgo web para almacenarlas en una base de datos local o en memoria. Las URLs se pueden comprobar localmente. Cuando se encuentra una coincidencia en la base de datos local, el cliente envía una solicitud a los servidores de Web Risk para verificar si la URL está incluida en las listas de Web Risk.

Actualizar la base de datos local

Para estar al día, los clientes deben actualizar periódicamente las listas de riesgo web en su base de datos local. Para ahorrar ancho de banda, los clientes descargan los prefijos de hash de las URLs en lugar de las URLs sin procesar. Por ejemplo, si "www.badurl.com/" está en una lista de Web Risk, los clientes descargan el prefijo de hash SHA256 de esa URL en lugar de la URL en sí. En la mayoría de los casos, los prefijos hash tienen una longitud de 4 bytes, lo que significa que el coste medio de ancho de banda de descargar una sola entrada de la lista es de 4 bytes antes de la compresión.

Para actualizar las listas de Web Risk en la base de datos local, envía una solicitud HTTP GET al método threatLists.computeDiff:

  • La solicitud HTTP GET incluye el nombre de la lista que se va a actualizar, así como las restricciones del cliente para tener en cuenta las limitaciones de memoria y ancho de banda.
  • La respuesta HTTP GET devuelve una actualización completa o parcial. La respuesta también puede devolver un tiempo de espera recomendado hasta la siguiente operación de cálculo de diferencias.

Ejemplo: threatLists.computeDiff

Solicitud HTTP GET

En el ejemplo siguiente, se solicitan las diferencias de la lista MALWARE de Web Risk. Para obtener más información, consulta los parámetros de consulta threatLists.computeDiff y las explicaciones que aparecen después del ejemplo de código.

Método HTTP y 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 tu solicitud, elige una de estas opciones:

curl

Ejecuta el comando siguiente:

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

Ejecuta el comando siguiente:

$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

Deberías recibir una respuesta JSON similar a la siguiente:

{
  "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 de Web Risk

El campo threatType identifica la lista de Web Risk. En el ejemplo, se solicitan las diferencias de la lista de Web Risk MALWARE.

Token de versión

El campo versionToken contiene el estado actual del cliente de la lista de Web Risk. Los tokens de versión se devuelven en el campo newVersionToken de la respuesta threatLists.computeDiff. Para las actualizaciones iniciales, deje el campo versionToken vacío.

Restricciones de tamaño

El campo maxDiffEntries especifica el número total de actualizaciones que puede gestionar el cliente (en el ejemplo, 2048). El campo maxDatabaseEntries especifica el número total de entradas que puede gestionar la base de datos local (en el ejemplo, 4096). Los clientes deben definir restricciones de tamaño para proteger la memoria y las limitaciones de ancho de banda, así como para evitar que las listas crezcan demasiado. Para obtener más información, consulta Update Constraints (Restricciones de actualización).

Compresiones admitidas

El campo supportedCompressions muestra los tipos de compresión que admite el cliente. En el ejemplo, el cliente solo admite datos sin comprimir. Sin embargo, Web Risk admite otros tipos de compresión. Para obtener más información, consulta Compresión.

Respuesta HTTP GET

En este ejemplo, la respuesta devuelve una actualización parcial de la lista de Riesgo web con el tipo de compresión solicitado.

Cuerpo de la respuesta

El cuerpo de la respuesta incluye la información de las diferencias (el tipo de respuesta, las adiciones y eliminaciones que se deben aplicar a la base de datos local, el nuevo token de versión y una suma de comprobación).

En el ejemplo, la respuesta también incluye el tiempo recomendado para la siguiente diferencia. Para obtener más información, consulta el cuerpo de la respuesta threatLists.computeDiff y las explicaciones que aparecen después del ejemplo 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"
}

Diferencias de bases de datos

El campo responseType indicará si se trata de una actualización parcial (DIFF) o completa (RESET). En el ejemplo, se devuelven diferencias parciales, por lo que la respuesta incluye tanto adiciones como eliminaciones. Puede haber varios conjuntos de adiciones, pero solo un conjunto de eliminaciones. Para obtener más información, consulta Diferencias de bases de datos.

Token de nueva versión

El campo newVersionToken contiene el token de la nueva versión de la lista de Web Risk recién actualizada. Los clientes deben guardar el nuevo estado del cliente para las solicitudes de actualización posteriores (el campo versionToken de la solicitud threatLists.computeDiff).

sumas de comprobación.

La suma de comprobación permite a los clientes verificar que la base de datos local no se ha dañado. Si la suma de comprobación no coincide, el cliente debe borrar la base de datos y volver a emitir una actualización con un campo versionToken vacío. Sin embargo, los clientes que se encuentren en esta situación deben seguir los intervalos de tiempo para las actualizaciones. Para obtener más información, consulta el artículo Frecuencia de las solicitudes.

El campo recommendedNextDiff indica una marca de tiempo hasta la que debe esperar el cliente antes de enviar otra solicitud de actualización. Ten en cuenta que el periodo de espera recomendado puede o no incluirse en la respuesta. Para obtener más información, consulta Frecuencia de solicitudes.

Comprobando URLs

Para comprobar si una URL está en una lista de Web Risk, el cliente debe calcular primero el hash y el prefijo de hash de la URL. Para obtener más información, consulta URLs y cifrado con hash. A continuación, el cliente consulta la base de datos local para determinar si hay alguna coincidencia. Si el prefijo de hash no está presente en la base de datos local, se considera que la URL es segura (es decir, que no está en las listas de Web Risk).

Si el prefijo de hash está presente en la base de datos local (una colisión de prefijos de hash), el cliente debe enviar el prefijo de hash a los servidores de Web Risk para que lo verifiquen. Los servidores devolverán todos los hashes SHA-256 de longitud completa que contengan el prefijo de hash proporcionado. Si una de esas versiones completas coincide con la versión completa de la URL en cuestión, se considera que la URL no es segura. Si ninguno de los hashes de longitud completa coincide con el hash de longitud completa de la URL en cuestión, se considera que esa URL es segura.

Google no conoce en ningún momento las URLs que examinas. Google aprende los prefijos cifrados con hash de las URLs, pero estos prefijos no proporcionan mucha información sobre las URLs reales.

Para comprobar si una URL está en una lista de Web Risk, envía una solicitud HTTP GET al método hashes.search:

  • La solicitud HTTP GET incluye el prefijo hash de la URL que se va a comprobar.
  • La respuesta HTTP GET devuelve los hashes de longitud completa coincidentes junto con los tiempos de vencimiento positivos y negativos.

Ejemplo: hashes.search

Solicitud HTTP GET

En el siguiente ejemplo, se envían los nombres de dos listas de Riesgo web y un prefijo de hash para compararlos y verificarlos. Para obtener más información, consulta los parámetros de consulta hashes.search y las explicaciones que aparecen después del ejemplo 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 de Web Risk

El campo threatTypes identifica las listas de Web Risk. En el ejemplo, se identifican dos listas: MALWARE y SOCIAL_ENGINEERING.

Prefijos de hash de amenazas

El campo hashPrefix contiene el prefijo hash de la URL que quieres comprobar. Este campo debe contener el prefijo de hash exacto que se encuentra en la base de datos local. Por ejemplo, si el prefijo de hash local tiene una longitud de 4 bytes, el campo hashPrefix debe tener una longitud de 4 bytes. Si el prefijo de hash local se ha ampliado a 7 bytes, el campo hashPrefix debe tener una longitud de 7 bytes.

Respuesta HTTP GET

En el siguiente ejemplo, la respuesta devuelve las amenazas coincidentes, que contienen las listas de Web Risk con las que coinciden, junto con los tiempos de vencimiento.

Cuerpo de la respuesta

El cuerpo de la respuesta incluye la información de la coincidencia (los nombres de las listas, los hashes de longitud completa y las duraciones de la caché). Para obtener más información, consulta el cuerpo de la respuesta hashes.search y las explicaciones que aparecen después del ejemplo 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"
}

Coincide con

El campo threats devuelve un hash de longitud completa que coincide con el prefijo del hash. Las URLs correspondientes a estos hashes se consideran no seguras. Si no se encuentra ninguna coincidencia para un prefijo de hash, no se devuelve nada y la URL correspondiente a ese prefijo de hash se considera segura.

Caducidad

Los campos expireTime y negativeExpireTime indican hasta cuándo se deben considerar los hashes como no seguros o seguros, respectivamente. Para obtener más información, consulta Almacenamiento en caché.