שימוש ב-Update API

סקירה כללית

באמצעות Update API, אפליקציות לקוח יכולות להוריד גרסאות מגובבות של רשימות Web Risk לאחסון במסד נתונים מקומי או בזיכרון. אחר כך אפשר לבדוק את כתובות ה-URL באופן מקומי. אם נמצאת התאמה במסד הנתונים המקומי, הלקוח שולח בקשה לשרתי Web Risk כדי לבדוק אם כתובת ה-URL כלולה ברשימות Web Risk.

עדכון של מסד הנתונים המקומי

כדי שהלקוחות יוכלו להישאר מעודכנים, הם צריכים לעדכן מעת לעת את רשימות Web Risk במסד הנתונים המקומי שלהם. כדי לחסוך ברוחב פס, הלקוחות מורידים את הקידומות של הגיבוב של כתובות ה-URL ולא את כתובות ה-URL הגולמיות. לדוגמה, אם כתובת ה-URL www.badurl.com/ נמצאת ברשימת הסיכונים באינטרנט, הלקוחות מורידים את הקידומת של הגיבוב SHA256 של כתובת ה-URL הזו ולא את כתובת ה-URL עצמה. ברוב המקרים, קידומות הגיבוב הן באורך 4 בייטים, כלומר עלות רוחב הפס הממוצעת של הורדת רשומה יחידה ברשימה היא 4 בייטים לפני הדחיסה.

כדי לעדכן את הרשימות של Web Risk במסד הנתונים המקומי, שולחים בקשת HTTP GET לשיטה threatLists.computeDiff:

  • בקשת ה-HTTP GET כוללת את שם הרשימה שצריך לעדכן, יחד עם אילוצים של הלקוח שמתייחסים למגבלות של הזיכרון ורוחב הפס.
  • התגובה של HTTP GET מחזירה עדכון מלא או עדכון חלקי. התשובה יכולה גם להחזיר זמן המתנה מומלץ עד לפעולת חישוב ההפרש הבאה.

דוגמה: threatLists.computeDiff

בקשת HTTP GET

בדוגמה הבאה, מוצגות בקשות להבדלים ברשימת הסיכונים באינטרנט של תוכנות זדוניות. פרטים נוספים זמינים בקטע threatLists.computeDiff פרמטרים של שאילתות ובהסברים שמופיעים אחרי דוגמת הקוד.

ה-method של ה-HTTP וכתובת ה-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

כדי לשלוח את הבקשה אתם צריכים לבחור אחת מהאפשרויות הבאות:

curl

מריצים את הפקודה הבאה:

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

מריצים את הפקודה הבאה:

$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

אתם אמורים לקבל תגובת JSON שדומה לזו:

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

רשימות Web Risk

השדה threatType מזהה את רשימת Web Risk. בדוגמה, מוצגות בקשות להבדלים ברשימת הסיכונים באינטרנט של תוכנות זדוניות.

טוקן גרסה

השדה versionToken מכיל את מצב הלקוח הנוכחי של רשימת Web Risk. אסימוני הגרסה מוחזרים בשדה newVersionToken של התשובה threatLists.computeDiff. לעדכונים ראשוניים, משאירים את השדה versionToken ריק.

מגבלות גודל

בשדה maxDiffEntries מצוין המספר הכולל של עדכונים שהלקוח יכול לנהל (בדוגמה, 2048). בשדה maxDatabaseEntries מציינים את המספר הכולל של הרשומות שמסד הנתונים המקומי יכול לנהל (בדוגמה, 4096). הלקוחות צריכים להגדיר מגבלות גודל כדי להגן על הזיכרון ועל מגבלות רוחב הפס, וכדי למנוע את הגידול ברשימה. מידע נוסף זמין במאמר בנושא אילוצים לעדכון).

סוגי דחיסה נתמכים

בשדה supportedCompressions מפורטים סוגי הדחיסה שהלקוח תומך בהם. בדוגמה, הלקוח תומך רק בנתונים גולמיים ולא דחוסים. עם זאת, Web Risk תומך בסוגי דחיסה נוספים. מידע נוסף זמין במאמר בנושא דחיסה.

תגובת HTTP GET

בדוגמה הזו, התגובה מחזירה עדכון חלקי לרשימת Web Risk באמצעות סוג הדחיסה המבוקש.

גוף התשובה

גוף התגובה כולל את פרטי ההבדלים (סוג התגובה, התוספות וההסרות שיש להחיל על מסד הנתונים המקומי, טוקן הגרסה החדשה וסכום ביקורת).

בדוגמה, התגובה כוללת גם את הזמן המומלץ להפרש הבא. פרטים נוספים מופיעים בקטע threatLists.computeDiff גוף התגובה ובהסברים שמופיעים אחרי קטע הקוד לדוגמה.

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

הבדלים בין מסדי נתונים

השדה responseType יציין אם מדובר בעדכון חלקי (DIFF) או מלא (RESET). בדוגמה, מוחזרים הבדלים חלקיים, ולכן התשובה כוללת גם הוספות וגם הסרות. יכולות להיות כמה קבוצות של תוספות, אבל רק קבוצה אחת של הסרות. מידע נוסף זמין במאמר בנושא השוואות בין מסדי נתונים.

טוקן של גרסה חדשה

בשדה newVersionToken מופיע אסימון הגרסה החדשה של רשימת Web Risk שעודכנה לאחרונה. הלקוחות צריכים לשמור את מצב הלקוח החדש כדי להשתמש בו בבקשות עדכון עתידיות (השדה versionToken בבקשת threatLists.computeDiff).

סכומי ביקורת

סכום הביקורת מאפשר ללקוחות לוודא שלא חל שיבוש במסד הנתונים המקומי. אם סיכום הביקורת לא תואם, הלקוח צריך לנקות את מסד הנתונים ולהנפיק מחדש עדכון עם שדה versionToken ריק. עם זאת, לקוחות שנמצאים במצב הזה עדיין צריכים לפעול בהתאם למרווחי הזמן לעדכונים. מידע נוסף זמין במאמר בנושא תדירות הבקשות.

השדה recommendedNextDiff מציין חותמת זמן שעד אליה הלקוח צריך להמתין לפני שליחת בקשת עדכון נוספת. שימו לב: יכול להיות שתקופת ההמתנה המומלצת תופיע בתגובה, ויכול להיות שלא. פרטים נוספים זמינים במאמר בנושא תדירות הבקשות.

בדיקת כתובות URL

כדי לבדוק אם כתובת URL מופיעה ברשימה של Web Risk, הלקוח צריך קודם לחשב את הגיבוב ואת קידומת הגיבוב של כתובת ה-URL. פרטים נוספים זמינים במאמר בנושא כתובות URL וגיבוב. לאחר מכן הלקוח שולח שאילתה למסד הנתונים המקומי כדי לבדוק אם יש התאמה. אם קידומת הגיבוב לא מופיעה במסד הנתונים המקומי, כתובת ה-URL נחשבת בטוחה (כלומר, היא לא מופיעה ברשימות של Web Risk).

אם קידומת הגיבוב קיימת במסד הנתונים המקומי (התנגשות של קידומת גיבוב ), הלקוח צריך לשלוח את קידומת הגיבוב לשרתי Web Risk לצורך אימות. השרתים יחזירו את כל הגיבובים המלאים בפורמט SHA 256 שמכילים את הקידומת הנתונה של הגיבוב. אם אחד מהגיבובים באורך מלא תואם לגיבוב באורך מלא של כתובת ה-URL הרלוונטית, כתובת ה-URL נחשבת ללא בטוחה. אם אף אחד מהגיבובים באורך מלא לא תואם לגיבוב באורך מלא של כתובת ה-URL הרלוונטית, כתובת ה-URL הזו נחשבת בטוחה.

במהלך הבדיקה, Google לא מקבלת מידע על כתובות ה-URL שאתם בודקים. ‫Google לומדת את התחיליות של הגיבוב של כתובות URL, אבל התחיליות האלה לא מספקות הרבה מידע על כתובות ה-URL בפועל.

כדי לבדוק אם כתובת URL מופיעה ברשימת Web Risk, שולחים בקשת HTTP GET לשיטה hashes.search:

  • בקשת ה-HTTP GET כוללת את קידומת הגיבוב של כתובת ה-URL שרוצים לבדוק.
  • תגובת ה-HTTP GET מחזירה את הגיבובים התואמים באורך מלא, יחד עם זמני התפוגה החיוביים והשליליים.

דוגמה: hashes.search

בקשת HTTP GET

בדוגמה הבאה, השמות של שתי רשימות של Web Risk וקידומת hash נשלחים להשוואה ולאימות. פרטים נוספים זמינים בקטע hashes.search פרמטרים של שאילתות ובהסברים שמופיעים אחרי דוגמת הקוד.

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

רשימות Web Risk

השדה threatTypes מציין את הרשימות של Web Risk. בדוגמה, מזוהות שתי רשימות: MALWARE ו-SOCIAL_ENGINEERING.

קידומות גיבוב (Hash) של איומים

השדה hashPrefix מכיל את קידומת הגיבוב של כתובת ה-URL שרוצים לבדוק. השדה הזה חייב להכיל את קידומת הגיבוב המדויקת שמופיעה במסד הנתונים המקומי. לדוגמה, אם קידומת הגיבוב המקומית היא באורך 4 בייט, השדה hashPrefix צריך להיות באורך 4 בייט. אם קידומת הגיבוב המקומית הוארכה ל-7 בייט, השדה hashPrefix חייב להיות באורך 7 בייט.

תגובת HTTP GET

בדוגמה הבאה, התגובה מחזירה את האיומים התואמים, כולל רשימות Web Risk שהם תואמים להן, וגם את זמני התפוגה.

גוף התשובה

גוף התשובה כולל את פרטי ההתאמה (שמות הרשימות, הגיבובים באורך מלא ומשך השהייה במטמון). פרטים נוספים מופיעים בקטע hashes.search גוף התגובה ובהסברים שמופיעים אחרי קטע הקוד לדוגמה.

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

התאמות

השדה threats מחזיר גיבובים מלאים שתואמים לקידומת הגיבוב. כתובות ה-URL שתואמות לגיבובים האלה נחשבות ללא בטוחות. אם לא נמצאה התאמה לקידומת הגיבוב, לא מוחזר דבר, וכתובת ה-URL שמתאימה לקידומת הגיבוב הזו נחשבת בטוחה.

מועד התפוגה

בשדות expireTime ו-negativeExpireTime מצוין עד מתי צריך להתייחס לגיבובים כלא בטוחים או כבטוחים, בהתאמה. פרטים נוספים זמינים במאמר בנושא שמירה במטמון.