Utiliser l'API Update

Présentation

L'API Update permet à vos applications clientes de télécharger une version hachée des listes Web Risk en vue de les stocker dans une base de données locale ou en mémoire. Les URL peuvent ensuite être vérifiées localement. Lorsqu'une correspondance est détectée dans la base de données locale, le client envoie une requête aux serveurs Web Risk pour vérifier si l'URL figure sur les listes Web Risk.

Mettre à jour la base de données locale

Pour rester à jour, les clients doivent régulièrement mettre à jour les listes Web Risk dans leur base de données locale. Pour économiser la bande passante, les clients téléchargent les préfixes de hachage des URL plutôt que les URL brutes. Par exemple, si "www.badurl.com/" figure sur une liste Web Risk, les clients téléchargent le préfixe de hachage SHA-256 de cette URL plutôt que l'URL elle-même. Dans la majorité des cas, les préfixes de hachage peuvent comporter 4 octets, ce qui signifie que le coût moyen en termes de bande passante pour le téléchargement d'une seule entrée de liste équivaut à 4 octets avant compression.

Pour mettre à jour les listes Web Risk dans la base de données locale, envoyez une requête HTTP GET à la méthode threatLists.computeDiff :

  • La requête HTTP GET inclut le nom de la liste à mettre à jour ainsi que les contraintes du client pour tenir compte des limites de mémoire et de bande passante.
  • La réponse HTTP GET renvoie une mise à jour complète ou partielle. La réponse pourrait également renvoyer un temps d'attente recommandé jusqu'à la prochaine opération de calcul des différences.

Exemple : threatLists.computeDiff

Requête HTTP GET

Dans l'exemple ci-dessous, les différences de la liste des logiciels malveillants Web Risk sont demandées. Pour plus de détails, consultez les paramètres de requête threatLists.computeDiff et les explications qui suivent l'exemple de code.

Méthode HTTP et 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

Pour envoyer votre requête, choisissez l'une des options suivantes :

curl

Exécutez la commande suivante :

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

Exécutez la commande suivante :

$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

Vous devriez recevoir une réponse JSON de ce type :

{
  "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

Listes Web Risk

Le champ threatType identifie la liste Web Risk. Dans cet exemple, les différences de la liste des logiciels malveillants Web Risk sont demandées.

Jeton de version

Le champ versionToken contient l'état actuel du client de la liste Web Risk. Les jetons de version sont renvoyés vers le champ newVersionToken de la réponse threatLists.computeDiff. Pour les mises à jour initiales, laissez le champ versionToken vide.

Contraintes de taille

Le champ maxDiffEntries spécifie le nombre total de mises à jour que le client peut gérer (dans l'exemple : 2 048). Le champ maxDatabaseEntries spécifie le nombre total d'entrées que la base de données locale peut gérer (dans l'exemple : 4 096). Les clients doivent définir des contraintes de taille pour protéger les limites de mémoire et de bande passante, et pour éviter la croissance de la liste. Pour en savoir plus, consultez la section Contraintes de mise à jour.

Compressions acceptées

Le champ supportedCompressions répertorie les types de compression compatibles avec le client. Dans l'exemple, le client n'accepte que les données brutes non compressées. Toutefois, Web Risk est compatible avec d'autres types de compression. Pour en savoir plus, consultez la section Compression.

Réponse HTTP GET

Dans cet exemple, la réponse renvoie une mise à jour partielle de la liste Web Risk à l'aide du type de compression demandé.

Corps de la réponse

Le corps de la réponse inclut des informations sur les différences (le type de réponse, les ajouts et les suppressions à appliquer à la base de données locale, le nouveau jeton de version et une somme de contrôle).

Dans l'exemple, la réponse inclut également le délai recommandé jusqu'à la prochaine différence. Pour plus de détails, consultez le corps de la réponse threatLists.computeDiff et les explications qui suivent l'exemple de code.

{
  "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"
}

Différences de bases de données

Le champ responseType indique une mise à jour partielle (DIFF) ou complète (RESET). Dans l'exemple, les différences partielles sont renvoyées. La réponse inclut donc les ajouts et les suppressions. Il peut y avoir plusieurs ensembles d'ajouts, mais un seul ensemble de suppressions. Pour en savoir plus, consultez la section Différences de bases de données.

Nouveau jeton de version

Le champ newVersionToken contient le nouveau jeton de version de la liste Web Risk récemment mise à jour. Les clients doivent enregistrer le nouvel état du client pour les demandes de mise à jour ultérieures (le champ versionToken dans la requête threatLists.computeDiff).

Sommes de contrôle

Les sommes de contrôle permettent aux clients de vérifier que la base de données locale n'a pas été corrompue. Si les sommes de contrôle ne correspondent pas, le client doit effacer la base de données et effectuer de nouveau une mise à jour avec un champ versionToken vide. Dans cette situation, les clients doivent cependant toujours suivre les intervalles de temps pour les mises à jour. Pour en savoir plus, consultez la section Fréquence des requêtes.

Le champ recommendedNextDiff contient un horodatage indiquant au client combien de temps il doit attendre avant d'envoyer une autre demande de mise à jour. Notez que le délai d'attente recommandé peut ou non être inclus dans la réponse. Pour en savoir plus, consultez la section Fréquence des requêtes.

Vérification des URL

Pour vérifier si une URL figure sur une liste Web Risk, le client doit d'abord calculer le hachage et le préfixe de hachage de l'URL. Pour en savoir plus, consultez la section URL et hachage. Le client interroge ensuite la base de données locale pour déterminer s'il existe une correspondance. Si le préfixe de hachage n'est pas présent dans la base de données locale, l'URL est considérée comme sécurisée (c'est-à-dire qu'elle ne figure pas sur les listes Web Risk).

Si le préfixe de hachage est présent dans la base de données locale (conflit de préfixe de hachage), le client doit l'envoyer aux serveurs Web Risk pour vérification. Les serveurs renvoient tous les hachages SHA-256 complets contenant un préfixe de hachage donné. Si l'un de ces hachages complets correspond au hachage complet de l'URL en question, cette dernière est considérée comme non sécurisée. Si aucun des hachages complets ne correspond au hachage complet de l'URL en question, cette dernière est considérée comme sécurisée.

À aucun moment, Google n'a connaissance des URL que vous examinez. Google a connaissance des préfixes de hachage des URL, mais ceux-ci ne fournissent pas beaucoup d'informations sur les URL réelles.

Pour vérifier si une URL figure sur une liste Web Risk, envoyez une requête HTTP GET à la méthode hashes.search :

  • La requête HTTP GET inclut le préfixe de hachage de l'URL à vérifier.
  • La réponse HTTP GET renvoie les hachages complets correspondants, ainsi que les délais d'expiration positifs et négatifs.

Exemple : hashes.search

Requête HTTP GET

Dans l'exemple suivant, les noms de deux listes Web Risk et un préfixe de hachage sont envoyés à des fins de comparaison et de vérification. Pour plus de détails, consultez les paramètres de requête hashes.search et les explications qui suivent l'exemple de code.

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

Listes Web Risk

Le champ threatTypes identifie les listes Web Risk. Dans l'exemple, deux listes sont identifiées: MALWARE et SOCIAL_ENGINEERING.

Préfixes de hachage des menaces

Le champ hashPrefix contient le préfixe de hachage de l'URL que vous souhaitez vérifier. Ce champ doit contenir le préfixe de hachage exact qui est présent dans la base de données locale. Par exemple, si le préfixe de hachage local comporte 4 octets, le champ hashPrefix doit aussi comporter 4 octets. Si le préfixe de hachage local a été rallongé et qu'il comporte maintenant 7 octets, le champ hashPrefix doit aussi comporter 7 octets.

Réponse HTTP GET

Dans l'exemple suivant, la réponse renvoie les menaces correspondantes, ainsi que les listes Web Risk où elles figurent et les délais d'expiration.

Corps de la réponse

Le corps de la réponse inclut des informations sur les correspondances (les noms de la liste, les hachages complets et les durées de mise en cache). Pour plus de détails, consultez le corps de la réponse hashes.search et les explications qui suivent l'exemple de code.

{
  "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"
}

Correspondances

Le champ threats renvoie le hachage complet correspondant au préfixe de hachage. Les URL correspondant à ces hachages sont considérées comme non sécurisées. Si aucune correspondance n'est trouvée pour un préfixe de hachage, aucune information n'est renvoyée. L'URL correspondant à ce préfixe de hachage est considérée comme sécurisée.

Date et heure d'expiration

Les champs expireTime et negativeExpireTime indiquent jusqu'à quel moment les hachages doivent être considérés comme sécurisés ou non sécurisés, selon le cas. Pour en savoir plus, consultez la section Cache.