使用 Security Command Center API 列出安全性發現項目

Security Command Center 發現項目會模擬專案或機構中資產的潛在安全性風險。發現項目一律與 Security Command Center 中的特定資產相關。

本指南說明如何使用 Security Command Center 用戶端程式庫存取發現項目。每項發現都屬於一個來源。大多數偵測工具或發現項目供應商都會在同一個來源中產生發現項目。

您可以在機構、資料夾或專案層級授予 Security Command Center 的 IAM 角色。您能否查看、編輯、建立或更新發現項目、資產和安全性來源,取決於您獲准的存取層級。如要進一步瞭解 Security Command Center 角色,請參閱存取權控管

事前準備

設定來源前,請先完成下列步驟:

頁面大小

所有 Security Command Center 清單 API 都會分頁。每個回應都會傳回一頁結果和一個符記,用來傳回下一頁。頁面大小可設定。 預設頁面大小為 10。你可以將這個值設為 1 到 1000。

發現項目保留期限

視 Security Command Center 方案而定,您可以在特定時間範圍內列出或查詢調查結果。如要進一步瞭解 Security Command Center 資料保留機制,請參閱「資料保留」。

列出所有發現項目

gcloud

如要列出專案、資料夾或機構中的所有調查結果,請執行下列指令:

gcloud scc findings list PARENT_TYPE/PARENT_ID \
  --location=LOCATION

更改下列內容:

  • PARENT_TYPE:要列出調查結果的資源階層層級;請使用 organizationsfoldersprojects
  • PARENT_ID:機構、資料夾或專案的數值 ID,或是英數字元組成的專案 ID。
  • LOCATION:要列出調查結果的Security Command Center 位置;如果已啟用資料落地功能,請使用 euksaus;否則請使用 global 值。

如需更多範例,請執行:

gcloud scc findings list --help

如需說明文件中的範例,請參閱 gcloud scc findings list

Go

import (
	"context"
	"fmt"
	"io"

	securitycenter "cloud.google.com/go/securitycenter/apiv2"
	"cloud.google.com/go/securitycenter/apiv2/securitycenterpb"
	"google.golang.org/api/iterator"
)

// listFindings prints all findings in orgID to w. orgID is the numeric
// identifier of the organization.
func listFindings(w io.Writer, orgID string) error {
	// orgID := "12321311"
	// Instantiate a context and a security service client to make API calls.
	ctx := context.Background()
	client, err := securitycenter.NewClient(ctx)
	if err != nil {
		return fmt.Errorf("securitycenter.NewClient: %w", err)
	}
	defer client.Close() // Closing the client safely cleans up background resources.

	req := &securitycenterpb.ListFindingsRequest{
		// List findings across all sources.
		// Parent must be in one of the following formats:
		//		"organizations/{orgId}/sources/-/locations/global"
		//		"projects/{projectId}/sources/-/locations/global"
		//		"folders/{folderId}/sources/-/locations/global"
		Parent: fmt.Sprintf("organizations/%s/sources/-/locations/global", orgID),
	}
	it := client.ListFindings(ctx, req)
	for {
		result, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return fmt.Errorf("it.Next: %w", err)
		}
		finding := result.Finding
		fmt.Fprintf(w, "Finding Name: %s, ", finding.Name)
		fmt.Fprintf(w, "Resource Name %s, ", finding.ResourceName)
		fmt.Fprintf(w, "Category: %s\n", finding.Category)
	}
	return nil
}

Java


import com.google.cloud.securitycenter.v2.ListFindingsRequest;
import com.google.cloud.securitycenter.v2.ListFindingsResponse.ListFindingsResult;
import com.google.cloud.securitycenter.v2.SecurityCenterClient;
import java.io.IOException;

public class ListAllFindings {

  public static void main(String[] args) throws IOException {
    // organizationId: The source to list all findings for.
    // You can also use project/ folder as the parent resource.
    String organizationId = "google-cloud-organization-id";

    // Specify the location to list the findings.
    String location = "global";

    // The source id to scope the findings.
    String sourceId = "source-id";

    listAllFindings(organizationId, sourceId, location);
  }

  // List all findings under a given parent resource.
  public static void listAllFindings(String organizationId, String sourceId, String location)
      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.
    try (SecurityCenterClient client = SecurityCenterClient.create()) {
      ListFindingsRequest request =
          ListFindingsRequest.newBuilder()
              // To list findings across all sources, use "-".
              .setParent(
                  String.format("organizations/%s/sources/%s/locations/%s", organizationId,
                      sourceId,
                      location))
              .build();

      for (ListFindingsResult result : client.listFindings(request).iterateAll()) {
        System.out.printf("Finding: %s", result.getFinding().getName());
      }
      System.out.println("\nListing complete.");
    }
  }
}

Node.js

// Imports the Google Cloud client library.
const {SecurityCenterClient} = require('@google-cloud/security-center').v2;

// Creates a new client.
const client = new SecurityCenterClient();

// TODO(developer): Update the following for your own environment.
const organizationId = '1081635000895';
const location = 'global';

// Required. Name of the source the findings belong to. If no location is
// specified, the default is global. The following list shows some examples:
// - `organizations/[organization_id]/sources/[source_id]/locations/[location_id]`
// - `folders/[folder_id]/sources/[source_id]`
// - `folders/[folder_id]/sources/[source_id]/locations/[location_id]`
// - `projects/[project_id]/sources/[source_id]`
// - `projects/[project_id]/sources/[source_id]/locations/[location_id]`
// To groupBy across all sources provide a source_id of `-`.
const parent = `organizations/${organizationId}/sources/-/locations/${location}`;

// Build the list findings request.
const listFindingsRequest = {
  parent,
};

async function listAllFindings() {
  // Call the API.
  const iterable = client.listFindingsAsync(listFindingsRequest);
  let count = 0;

  for await (const response of iterable) {
    // Just print a few for demonstration.
    if (count > 5) break;
    console.log(
      `${++count} ${response.finding.name} ${response.finding.resourceName}`
    );
  }
}

await listAllFindings();

Python

def list_all_findings(organization_id, source_name, location_id) -> int:
    """
    lists all findings for a source
    Args:
       organization_id: organization_id is the numeric ID of the organization. e.g.:organization_id = "111122222444"
       source_name: is the resource path for a source that has been created
       location_id: GCP location id; example: 'global'
    Returns:
        int: returns the count of all findings for a source
    """
    from google.cloud import securitycenter_v2

    # Create a client.
    client = securitycenter_v2.SecurityCenterClient()
    parent = f"organizations/{organization_id}"
    all_sources = f"{parent}/sources/{source_name}/locations/{location_id}"

    # Create the request dictionary
    request = {"parent": all_sources}

    # Print the request for debugging
    print("Request: ", request)

    finding_result_iterator = client.list_findings(request={"parent": all_sources})
    for count, finding_result in enumerate(finding_result_iterator):
        print(
            "{}: name: {} resource: {}".format(
                count, finding_result.finding.name, finding_result.finding.resource_name
            )
        )
    return finding_result_iterator

每項發現的輸出內容如下:

{
  "finding": {
    "name": "organizations/ORGANIZATION_ID/sources/SOURCE_ID/findings/FINDING_ID",
    "parent": "organizations/ORGANIZATION_ID/sources/SOURCE_ID",
    "resourceName": "//cloudresourcemanager.googleapis.com/projects/PROJECT_NUMBER",
    "state": "ACTIVE",
    "category": "Malware: Cryptomining Bad Domain",
    "sourceProperties": {
      "sourceId": {
        "projectNumber": "PROJECT_NUMBER",
        "customerOrganizationNumber": "ORGANIZATION_ID"
      },
      "detectionCategory": {
        "technique": "cryptomining",
        "indicator": "domain",
        "ruleName": "bad_domain",
        "subRuleName": "cryptomining"
      },
      "detectionPriority": "LOW",
      "affectedResources": [
        {
          "gcpResourceName": "//cloudresourcemanager.googleapis.com/projects/PROJECT_NUMBER"
        }
      ],
      "evidence": [
        {
          "sourceLogId": {
            "projectId": "PROJECT_ID",
            "resourceContainer": "projects/PROJECT_ID",
            "timestamp": {
              "seconds": "1636566099",
              "nanos": 5.41483849E8
            },
            "insertId": "INSERT_ID"
          }
        }
      ],
      "properties": {
        "domains": ["DOMAIN"],
        "instanceDetails": "/projects/PROJECT_ID/zones/ZONE/instances/INSTANCE_ID",
        "network": {
          "project": "PROJECT_ID",
          "location": "ZONE"
        },
        "dnsContexts": [
          {
            "authAnswer": true,
            "sourceIp": "SOURCE_IP_ADDRESS",
            "queryName": "DOMAIN",
            "queryType": "A",
            "responseCode": "NXDOMAIN"
          }
        ],
        "vpc": {
          "vpcName": "default"
        }
      },
      "findingId": "FINDING_ID",
      "contextUris": {
        "mitreUri": {
          "displayName": "MITRE Link",
          "url": "https://attack.mitre.org/techniques/T1496/"
        },
        "virustotalIndicatorQueryUri": [
          {
            "displayName": "VirusTotal Domain Link",
            "url": "https://www.virustotal.com/gui/domain/DOMAIN/detection"
          }
        ],
        "cloudLoggingQueryUri": [
          {
            "displayName": "Cloud Logging Query Link",
            "url": "https://console.cloud.google.com/logs/query;query\u003dtimestamp%3D%222021-11-10T17:41:39.541483849Z%22%0AinsertId%3D%22INSERT_ID%22%0Aresource.labels.project_id%3D%22PROJECT_ID%22?project\u003dPROJECT_ID"
          }
        ],
        "relatedFindingUri": {}
      }
    },
    "securityMarks": {
      "name": "organizations/ORGANIZATION_ID/sources/SOURCE_ID/findings/FINDING_ID/securityMarks"
    },
    "eventTime": "2021-11-10T17:41:41.594Z",
    "createTime": "2021-11-10T17:41:42.014Z",
    "severity": "LOW",
    "workflowState": "NEW",
    "canonicalName": "projects/PROJECT_NUMBER/sources/SOURCE_ID/findings/FINDING_ID",
    "mute": "UNDEFINED",
    "findingClass": "THREAT",
    "indicator": {
      "domains": ["DOMAIN"]
    }
  },
  "resource": {
    "name": "//cloudresourcemanager.googleapis.com/projects/PROJECT_NUMBER",
    "projectName": "//cloudresourcemanager.googleapis.com/projects/PROJECT_NUMBER",
    "projectDisplayName": "PROJECT_ID",
    "parentName": "//cloudresourcemanager.googleapis.com/organizations/ORGANIZATION_ID",
    "parentDisplayName": "PARENT_NAME",
    "type": "google.cloud.resourcemanager.Project",
    "displayName": "PROJECT_ID"
  }
}

篩選結果

專案、資料夾或機構可能會有許多發現項目。上例並未使用篩選器,因此系統會傳回所有發現記錄。

如要只取得所需欄位的資訊,可以使用尋找篩選器。這些篩選器類似於 SQL 陳述式中的「where」子句,但不是套用至資料欄,而是套用至 API 傳回的物件。

以下範例只列出類別為「MEDIUM_RISK_ONE」的調查結果。不同的調查結果提供者 (也稱為「安全性來源」) 使用不同的類別組合。如要判斷篩選器中可使用的類別,請參閱發現項目供應商的文件。

gcloud

使用下列指令篩選結果:

gcloud scc findings list PARENT_TYPE/PARENT_ID \
  --location=LOCATION \
  --source=SOURCE_ID \
  --filter="FILTER"

更改下列內容:

  • PARENT_TYPE:要列出調查結果的資源階層層級;請使用 organizationsfoldersprojects
  • PARENT_ID:機構、資料夾或專案的數值 ID,或是英數字元組成的專案 ID。
  • LOCATION:要列出篩選條件結果的 Security Command Center 位置;如果已啟用資料落地功能,請使用 euksaus;否則請使用 global 值。
  • SOURCE_ID:提供發現類型的安全來源 ID。
  • FILTER:您需要使用的篩選器。舉例來說,下列篩選器只會傳回 MEDIUM_RISK_ONE 類別的發現項目:
    --filter="category=\"MEDIUM_RISK_ONE\""

如需更多範例,請執行:

gcloud scc findings list --help

如需說明文件中的範例,請參閱 gcloud scc findings list

Go

import (
	"context"
	"fmt"
	"io"

	securitycenter "cloud.google.com/go/securitycenter/apiv2"
	"cloud.google.com/go/securitycenter/apiv2/securitycenterpb"
	"google.golang.org/api/iterator"
)

// listFilteredFindings prints findings with category 'MEDIUM_RISK_ONE' for a
// specific source to w. sourceName is the full resource name of the source
// to search for findings under.
func listFilteredFindings(w io.Writer, sourceName string) error {
	// Specific source:
	// 		sourceName := "{parent}/sources/{sourceId}"
	// All sources:
	// 		sourceName := "{parent}/sources/-"
	// where,
	// Parent must be in one of the following formats:
	//		"organizations/{orgId}"
	//		"projects/{projectId}"
	//		"folders/{folderId}"
	// Instantiate a context and a security service client to make API calls.
	ctx := context.Background()
	client, err := securitycenter.NewClient(ctx)
	if err != nil {
		return fmt.Errorf("securitycenter.NewClient: %w", err)
	}
	defer client.Close() // Closing the client safely cleans up background resources.

	req := &securitycenterpb.ListFindingsRequest{
		Parent: sourceName,
		Filter: `category="MEDIUM_RISK_ONE"`,
	}
	it := client.ListFindings(ctx, req)
	for {
		result, err := it.Next()
		if err == iterator.Done {
			break
		}
		if err != nil {
			return fmt.Errorf("it.Next: %w", err)
		}
		finding := result.Finding
		fmt.Fprintf(w, "Finding Name: %s, ", finding.Name)
		fmt.Fprintf(w, "Resource Name %s, ", finding.ResourceName)
		fmt.Fprintf(w, "Category: %s\n", finding.Category)
	}
	return nil
}

Java


import com.google.cloud.securitycenter.v2.ListFindingsRequest;
import com.google.cloud.securitycenter.v2.ListFindingsResponse.ListFindingsResult;
import com.google.cloud.securitycenter.v2.SecurityCenterClient;
import java.io.IOException;

public class ListFindingsWithFilter {

  public static void main(String[] args) throws IOException {
    // TODO: Replace the variables within {}
    // organizationId: Google Cloud Organization id.
    // You can also use project/ folder as the parent resource.
    String organizationId = "google-cloud-organization-id";

    // Specify the location to list the findings.
    String location = "global";

    // The source id to scope the findings.
    String sourceId = "source-id";

    listFilteredFindings(organizationId, sourceId, location);
  }

  // List filtered findings under a source.
  public static void listFilteredFindings(String organizationId, String sourceId, String location)
      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.
    try (SecurityCenterClient client = SecurityCenterClient.create()) {

      // Use any one of the following formats:
      //  * organizations/{organization_id}/sources/{source_id}/locations/{location}
      //  * folders/{folder_id}/sources/{source_id}/locations/{location}
      //  * projects/{project_id}/sources/{source_id}/locations/{location}
      String parent = String.format("organizations/%s/sources/%s/locations/%s", organizationId,
          sourceId,
          location);

      // Listing all findings of category "MEDIUM_RISK_ONE".
      String filter = "category=\"MEDIUM_RISK_ONE\"";

      ListFindingsRequest request =
          ListFindingsRequest.newBuilder()
              .setParent(parent)
              .setFilter(filter)
              .build();

      for (ListFindingsResult result : client.listFindings(request).iterateAll()) {
        System.out.printf("Finding: %s", result.getFinding().getName());
      }
      System.out.println("\nListing complete.");
    }
  }
}

Node.js

// Imports the Google Cloud client library.
const {SecurityCenterClient} = require('@google-cloud/security-center').v2;

// Creates a new client.
const client = new SecurityCenterClient();

// TODO(developer): Update the following for your own environment.
const organizationId = '1081635000895';
const location = 'global';

// Required. Name of the source to groupBy. If no location is specified,
// finding is assumed to be in global.
//  The following list shows some examples:
// - `organizations/[organization_id]/sources/[source_id]`
// - `organizations/[organization_id]/sources/[source_id]/locations/[location_id]`
// - `folders/[folder_id]/sources/[source_id]`
// - `folders/[folder_id]/sources/[source_id]/locations/[location_id]`
// - `projects/[project_id]/sources/[source_id]`
// - `projects/[project_id]/sources/[source_id]/locations/[location_id]`
// To groupBy across all sources provide a source_id of `-`.
const parent = `organizations/${organizationId}/sources/-/locations/${location}`;

// Listing all findings of category "MEDIUM_RISK_ONE".
const filter = 'category="MEDIUM_RISK_ONE"';

// Build the list findings with filter request.
const listFilteredFindingsRequest = {
  parent,
  filter,
};

async function listFilteredFindings() {
  // Call the API.
  const iterable = client.listFindingsAsync(listFilteredFindingsRequest);
  let count = 0;
  console.log('Findings:');
  for await (const response of iterable) {
    // Just print a few for demonstration.
    if (count > 5) break;
    console.log(
      `${++count} ${response.finding.name} ${response.finding.resourceName}`
    );
  }
}
await listFilteredFindings();

Python

def list_filtered_findings(organization_id, source_name, location_id) -> int:
    """
    lists filtered findings for a source
    Args:
        organization_id: organization_id is the numeric ID of the organization. e.g.:organization_id = "111122222444"
        source_name: is the resource path for a source that has been created
        location_id: GCP location id; example: 'global'
    Returns:
         int: returns the filtered findings for a source
    """
    count = 0
    from google.cloud import securitycenter_v2

    # Create a new client.
    client = securitycenter_v2.SecurityCenterClient()
    parent = f"organizations/{organization_id}"
    all_sources = f"{parent}/sources/{source_name}/locations/{location_id}"
    finding_result_iterator = client.list_findings(
        request={"parent": all_sources, "filter": 'severity="LOW"'}
    )
    # Iterate an print all finding names and the resource they are
    # in reference to.
    for count, finding_result in enumerate(finding_result_iterator):
        print(
            "{}: name: {} resource: {}".format(
                count, finding_result.finding.name, finding_result.finding.resource_name
            )
        )
    return count

Security Command Center 也支援完整的 JSON 陣列和物件,做為潛在的屬性型別。你可以依下列條件篩選:

  • 陣列元素
  • 在物件中部分比對字串的完整 JSON 物件
  • JSON 物件子欄位

支援的運算子

Security Command Center 發現項目的查詢陳述式支援大多數 Google Cloud API 支援的運算子。

以下清單顯示各種運算子的用法:

  • state="ACTIVE" AND NOT mute="MUTED"
  • create_time>"2023-08-15T19:05:32.428Z"
  • resource.parent_name:"prod"
  • severity="CRITICAL" OR severity="HIGH"

以下列出發現項目的查詢陳述式支援的所有運算子和函式:

  • 字串:
    • = 爭取完全平等
    • : (與部分字串相符)
  • 數字:
    • <><=>= (適用於不等式)
    • =!=,爭取平等
  • 布林值:
    • =,爭取平等
  • 邏輯關係:
    • AND
    • OR
    • NOT-
  • 運算式分組:
    • () (括號)
  • 陣列:
    • contains():這個函式可查詢結果,其中包含至少一個符合指定篩選條件的元素
    • containsOnly():這個函式可查詢結果,並找出只包含符合指定篩選條件元素的陣列欄位
  • IP 位址:
    • inIpRange():這個函式可以查詢指定 CIDR 範圍內的 IP 位址

依 IP 位址篩選

某些發現項目屬性包含 IP 位址。您可以根據特定 IP 位址或 IP 位址範圍篩選調查結果。

IP 位址會以字串形式出現在各種發現項目和發現項目屬性中,包括:

  • access.caller_ip
  • connections.destinationIp
  • connections.sourceIp
  • indicator.ip_addresses

如要依特定 IP 位址篩選,可以使用等號運算子,如下列範例所示:

access.caller_ip="192.0.2.0"

如要根據 IP 位址範圍篩選發現項目,請使用 inIpRange 函式。使用 inIpRange 函式篩選發現項目,只顯示包含指定 CIDR 範圍內 IP 位址的發現項目。使用 NOT 搭配 inIpRange 運算子,即可篩選發現項目,只顯示包含指定 CIDR 範圍外 IP 位址的發現項目。

以下範例顯示 inIpRange 函式的語法:

inIpRange(IP_FINDING_FIELD, "CIDR_RANGE")

如果 IP 位址位於含有陣列的發現項目欄位中,請使用下列語法搭配 contains 函式和 inIpRange 函式:

contains(ATTRIBUTE_WITH_ARRAY, inIpRange(IP_FINDING_FIELD, "CIDR_RANGE"))

在下列範例中,inIpRange 函式會評估 connections 尋找欄位中包含的陣列的每個 destination_ip 元素,找出位於 192.0.2.0/24 定義的 CIDR 範圍內的 IP 位址:

contains(connections, inIpRange(destination_ip, "192.0.2.0/24"))

以下範例顯示 gcloud CLI 指令,該指令使用 inIpRange 函式,篩選出 connections.source_ip 欄位中 IP 位址位於某個範圍內,但不在另一個範圍內的發現項目。connections 欄位是陣列型欄位,因此使用 contains 函式:

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --filter="contains(connections, inIpRange(source_ip, \"2001:db8::/32\")) \
      AND NOT contains(connections, inIpRange(source_ip, \"192.0.2.0/24\"))"

JSON 物件範例

本頁稍後的範例會假設下列 JSON 物件是發現項目屬性:

{
  "outer_object": {
    "middle_object": {
      "deeply_nested_object": {
        "x": 123
      },
      "y": "some-string-value"
    },
    "list_middle_object": [
      {
        "v": 321,
        "w": [
          {
            "a": 3,
            "b": 4
          }
        ]
      }
    ],
    "z": "some-other-string-value",
    "u": [
      "list-element-1",
      "list-element-2",
      "list-element-3"
    ]
  }
}

篩選發現項目範例

假設先前的 JSON 範例是名為 my_property 的發現項目屬性。下列範例包含以物件做為屬性的發現項目查詢。您也可以在查詢中搭配使用 ANDOR,將這些篩選器與其他篩選器合併使用。

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --filter="my_property.outer_object.middle_object.deeply_nested_object.x = 123"

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --filter="my_property.outer_object.middle_object.y = \"some-string-value\""

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --filter="my_property.outer_object.middle_object.y : \"string-value\""

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --filter="my_property.outer_object.z = \"some-other-string-value\""

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --filter="my_property.outer_object.z : \"other-string-value\""

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --filter="my_property.outer_object.u : \"list-element-1\""

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --filter="my_property.outer_object.u : \"list-element-2\""

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --filter="my_property.outer_object.u : \"list-element-3\""

陣列類型欄位的子篩選器

呼叫 ListFindings 時,可以使用子字串比對 :,針對陣列的整個內容進行單一檢查,判斷是否有部分字串相符。此外,您也可以使用下列任一函式,直接對陣列元素及其子欄位執行子篩選器:

  • 如果陣列的任何元素包含指定值,contains() 函式就會傳回結果。

  • containsOnly() 函式,只有在陣列的所有元素都符合子篩選器時,才會傳回結果。

這兩個函式都支援子篩選器查詢功能,例如:

  • 完全比對元素:比對含有完全相符字串的陣列元素,"example"
  • 特定數字運算:比對大於或等於 100 的陣列元素。
  • 針對陣列結構進行複雜篩選:比對含有屬性 x 的陣列元素與對應值 y

contains() 函式的格式

contains() 函式的格式如下:

contains(ARRAY_ATTRIBUTE_NAME, SUBFILTER)

更改下列內容:

  • ARRAY_ATTRIBUTE_NAME:屬於陣列 (清單) 類型的欄位或子欄位。
  • SUBFILTER:定義要在陣列中尋找的值的運算式。子篩選器的格式取決於 ARRAY_ATTRIBUTE_NAME物件陣列還是原始型別元素陣列。如果 ARRAY_ATTRIBUTE_NAME 是含有巢狀陣列的物件陣列,您可以使用範圍子篩選器,指定您希望在同一個 ARRAY_ATTRIBUTE_NAME 元素中滿足所有條件。

Security Command Center API 會傳回 ARRAY_ATTRIBUTE_NAME 包含至少一個滿足 SUBFILTER 的元素的發現項目。

containsOnly() 函式的格式

containsOnly() 函式的格式如下:

containsOnly(ARRAY_ATTRIBUTE_NAME, SUBFILTER)

更改下列內容:

  • ARRAY_ATTRIBUTE_NAME:屬於陣列 (清單) 類型的欄位或子欄位。使用 Security Command Center API 執行查詢時,您可以針對任何可用的陣列屬性使用 containsOnly() 函式。
  • SUBFILTER:定義要在陣列中尋找的值的運算式。子篩選器的格式取決於 ARRAY_ATTRIBUTE_NAME物件陣列還是基本型別元素陣列。如果 ARRAY_ATTRIBUTE_NAME 是含有巢狀陣列的物件陣列,您可以使用範圍子篩選器,指定您希望在同一個 ARRAY_ATTRIBUTE_NAME 元素中滿足所有條件。

如果所有 ARRAY_ATTRIBUTE_NAME 元素都與 SUBFILTER 相符,Security Command Center API 就會傳回發現項目。

物件陣列的子篩選器

以下是先前的 JSON 範例節錄內容。在此,list_middle_object 欄位是物件陣列:

    "list_middle_object": [
      {
        "v": 321,
        "w": [
          {
            "a": 3,
            "b": 4
          }
        ]
      }
    ]

以下範例會查詢 list_middle_object 欄位中至少有一個元素具有 v 子欄位,且值大於或等於 321 的調查結果:

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --filter="contains(my_property.outer_object.list_middle_object, v  >= 321)"

如需使用 contains()containsOnly() 函式的實用範例,請參閱「含有特定陣列值的結果」。

包含基本型別元素的陣列的子篩選器

原始型別為字串、數字和布林值。如要對含有原始型別的陣列使用 contains() 函式,請使用特殊關鍵字 elem

以下是先前的 JSON 範例節錄內容。這裡的 u 欄位是原始型別元素的陣列:

"u": ["list-element-1", "list-element-2", "list-element-3"]

以下範例會查詢 u 欄位中至少有一個元素為「list-element-1」的發現項目:

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --filter="contains(my_property.outer_object.u, elem = \"list-element-1\")"

如需使用 contains() 函式的實用範例,請參閱「含有特定陣列值的發現項目」。

限定範圍的子篩選器

以下是先前的 JSON 範例節錄內容。其中,list_middle_object 欄位是物件陣列,而這個陣列中的物件包含巢狀陣列。

"list_middle_object": [
  {
    "v": 321,
    "w": [
      {
        "a": 3,
        "b": 4
      }
    ]
  }
]

下列範例會查詢在同一個 list_middle_object 元素中,同時滿足下列兩個條件的發現事項:

  • v 子欄位的值大於或等於 321。
  • w 子欄位不含 a 屬性等於 3 的元素。
gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --filter="contains(my_property.outer_object.list_middle_object, v  >= 321 AND -contains(w, a = 3))"

如需使用 contains() 函式的實用範例,請參閱「含有特定陣列值的發現項目」。

排序發現項目範例

您可以依嚴格子欄位 (原始型別,例如字串、數字和布林值) 排序調查結果。假設先前的 JSON 範例是名為 my_property 的發現項目屬性。以下範例包含查詢,可排序結果欄位。關鍵字 DESC 會指定其後方的欄位必須依遞減順序排序。預設為遞增排序。

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --order-by="my_property.outer_object.middle_object.deeply_nested_object.x DESC"

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --order-by="my_property.outer_object.middle_object.deeply_nested_object.x"

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --order-by="my_property.outer_object.middle_object.y DESC"

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --order-by="my_property.outer_object.middle_object.y"

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --order-by="my_property.outer_object.z DESC"

gcloud scc findings list PARENT_TYPE/PARENT_ID \
    --location=LOCATION \
    --source=SOURCE_ID \
    --order-by="my_property.outer_object.z"

篩選器範例

以下各節將提供實用範例,說明如何尋找篩選器。

篩選特定時間之後的發現項目

這些範例篩選器會比對 2019 年 6 月 5 日星期三格林威治標準時間晚上 10:12:05 後發生的最新發現項目。使用 event_time 篩選器時,您可以透過下列格式和類型表示時間:

  • 以整數常值表示的 Unix Epoch 時間 (以毫秒為單位)

    "event_time > 1559772725000"
    
  • RFC 3339 (字串常值)

    "event_time > \"2019-06-05T22:34:40+00:00\""
    

篩選陣列型欄位

以下範例顯示如何在篩選器中,對陣列型別的欄位使用部分字串比對:

"indicator.domains : \"website.com\""

Security Command Center API 會傳回陣列中含有 website.com 部分字串的任何發現項目。舉例來說,這會比對含有 indicator.domains = [\"onewebsite.com\"] 的發現項目,因為「website.com」是陣列中某個元素內的子字串。

在下列各節中,範例篩選器會顯示使用 contains() 函式進行豐富陣列類型篩選的部分選項。

篩選 vulnerability.cve.references 欄位

以下範例會傳回結果,其中 vulnerability.cve.references 陣列至少有一個元素同時具有 source 屬性 (等於 SOURCE_OF_REFERENCE) 和 uri 屬性 (具有 FILTERED_URI)。

"contains(vulnerability.cve.references, source = \"SOURCE_OF_REFERENCE\" AND uri : \"FILTERED_URI\")"

更改下列內容:

  • SOURCE_OF_REFERENCE常見安全漏洞與弱點 (CVE) 參考資料的來源名稱,例如 NVD
  • FILTERED_URI:CVE 參照來源的 URI。

篩選 indicator.domains 欄位

以下範例會傳回至少有一個指標網域同時具有 mycompanyprefix.ca 的調查結果。

"contains(indicator.domains, elem : \"mycompanyprefix\" AND elem : \".ca\")"

篩選 indicator.ip_addresses 欄位

以下範例會傳回 indicator.ip_addresses 陣列中至少有一個元素等於 IP_ADDRESS 的結果。

"contains(indicator.ip_addresses, elem = \"IP_ADDRESS\")"

IP_ADDRESS 替換為與您要搜尋的調查結果相關聯的 IP 位址。

篩選外部系統指派對象

以下範例會傳回 external_systems.EXTERNAL_SYSTEM_NAME.assignees 陣列中至少有一個元素等於 ASSIGNEE 的結果。

"contains(external_systems.EXTERNAL_SYSTEM_NAME.assignees, elem = \"ASSIGNEE\")"

更改下列內容:

  • EXTERNAL_SYSTEM_NAME:第三方 SIEM/SOAR 系統的名稱,例如 demisto
  • ASSIGNEE:外部系統中的指派對象。

篩選 resource.folders.resource_folder 欄位

以下範例會傳回 resource.folders.resource_folder 陣列中至少有一個元素不等於 FOLDER_NAME 的結果。

"contains(resource.folders.resource_folder, -(elem = \"FOLDER_NAME\"))"

篩選 resource.folders.resource_folder_display_name 欄位

以下範例會傳回 resource.folders.resource_folder_display_name 陣列中至少有一個元素等於 DISPLAY_NAME 的結果。

"contains(resource.folders.resource_folder_display_name, elem = \"DISPLAY_NAME\")"

DISPLAY_NAME 替換為與您要搜尋的調查結果相關聯的資料夾使用者定義名稱。

篩選條件只包含特定服務帳戶

在下列範例中,只有當每個 iam_bindings 項目成員值都等於其中一個提供的服務帳戶時,才會傳回結果。

containsOnly(iam_bindings, (member = SERVICE_ACCOUNT1 OR member = SERVICE_ACCOUNT2 OR member = "SERVICE_ACCOUNT3 "))

SERVICE_ACCOUNT1SERVICE_ACCOUNT2SERVICE_ACCOUNT3 替換為服務帳戶的電子郵件地址。

如要瞭解如何在搜尋結果篩選器中使用 contains()containsOnly() 函式,請參閱陣列型欄位的子篩選器

後續步驟

進一步瞭解如何設定發現項目通知