根据路径或边缘数据计算目标节点的风险外围(列表和分数)。
函数 graph_exposure_perimeter_fl()
是 UDF(用户定义的函数),可用于根据路径或边缘数据计算每个目标节点的曝光外围。 输入数据的每一行都包含一个源节点和一个目标节点,可以表示节点和目标之间的直接连接(边缘),或者两者之间更长的多跃点路径。 如果路径不可用,我们首先可以使用 图形匹配 运算符或 graph_path_discovery_fl() 函数发现它们。 然后可以在路径发现输出的基础上执行 graph_exposure_perimeter_fl()
。
风险外围表示从相关源节点到特定目标的可访问性。 能够访问目标的源越多,遭到攻击者入侵后的可能性就越大,风险外围因此得名。 具有高风险外围的节点在网络安全域中非常重要,因为这些节点可能被非法访问,并且受到攻击者的高度重视。 因此,在强化和监视外围方面,应相应地保护具有高风险外围的节点。
该函数输出可访问每个目标的连接源列表以及代表目标数量的分数。 或者,如果每个源都有一个有意义的“权重”(例如漏洞或暴露性),则可以将加权分数计算为源权重的总和。 此外,为了更好地进行控制,显示目标的最大总数和每个列表中源最大数量的限制将作为可选参数公开。
语法
graph_exposure_perimeter_fl(
sourceIdColumnName、targetIdColumnName、[sourceWeightColumnName]、[resultCountLimit]、[listedIdsLimit])
详细了解语法约定。
参数
客户 | 类型 | 必需 | 说明 |
---|---|---|---|
sourceIdColumnName | string |
✔️ | 包含源节点 ID(边缘或路径)的列名称。 |
targetIdColumnName | string |
✔️ | 包含目标节点 ID(边缘或路径)的列名称。 |
sourceWeightColumnName | string |
包含源节点权重(例如漏洞)的列名称。 如果不存在相关权重,则加权分数为 0。 默认列名为“noWeightsColumn”。 | |
resultCountLimit | long |
返回的最大行数(按分数降序排序)。 默认值为 100000。 | |
listedIdsLimit | long |
为每个源列出的最大目标数。 默认值为 50。 |
函数定义
可以通过将函数的代码嵌入为查询定义的函数,或将其创建为数据库中的存储函数来定义函数,如下所示:
使用以下 let 语句定义函数。 不需要任何权限。
let exposure_perimeter_fl = (T:(*), sourceIdColumnName:string, targetIdColumnName:string, sourceWeightColumnName:string= 'noWeightsColumn'
, resultCountLimit:long = 100000, listedIdsLimit:long = 50)
{
let paths = (
T
| extend sourceId = column_ifexists(sourceIdColumnName, '')
| extend targetId = column_ifexists(targetIdColumnName, '')
| extend sourceWeight = tolong(column_ifexists(sourceWeightColumnName, 0))
);
let aggregatedPaths = (
paths
| sort by targetId, sourceWeight desc
| summarize exposurePerimeterList = array_slice(make_set_if(sourceId, isnotempty(sourceId)), 0, (listedIdsLimit - 1))
, exposurePerimeterScore = dcountif(sourceId, isnotempty(sourceId))
, exposurePerimeterScoreWeighted = sum(sourceWeight)
by targetId
| extend isExposurePerimeterCapped = (exposurePerimeterScore > listedIdsLimit)
);
aggregatedPaths
| top resultCountLimit by exposurePerimeterScore desc
};
// Write your query to use the function here.
示例
以下示例使用 invoke 运算符运行函数。
若要使用查询定义的函数,请在嵌入的函数定义后调用它。
let connections = datatable (SourceNodeName:string, TargetNodeName:string, SourceNodeVulnerability:int)[
'vm-work-1', 'webapp-prd', 0,
'vm-custom', 'webapp-prd', 4,
'webapp-prd', 'vm-custom', 1,
'webapp-prd', 'test-machine', 1,
'vm-custom', 'server-0126', 4,
'vm-custom', 'hub_router', 4,
'webapp-prd', 'hub_router', 2,
'test-machine', 'vm-custom', 5,
'test-machine', 'hub_router', 5,
'hub_router', 'remote_DT', 0,
'vm-work-1', 'storage_main_backup', 0,
'hub_router', 'vm-work-2', 0,
'vm-work-2', 'backup_prc', 1,
'remote_DT', 'backup_prc', 2,
'backup_prc', 'storage_main_backup', 0,
'backup_prc', 'storage_DevBox', 0,
'device_A1', 'sevice_B2', 1,
'sevice_B2', 'device_A1', 2
];
let exposure_perimeter_fl = (T:(*), sourceIdColumnName:string, targetIdColumnName:string, sourceWeightColumnName:string = 'noWeightsColumn'
, resultCountLimit:long = 100000, listedIdsLimit:long = 50)
{
let paths = (
T
| extend sourceId = column_ifexists(sourceIdColumnName, '')
| extend targetId = column_ifexists(targetIdColumnName, '')
| extend sourceWeight = tolong(column_ifexists(sourceWeightColumnName, 0))
);
let aggregatedPaths = (
paths
| sort by targetId, sourceWeight desc
| summarize exposurePerimeterList = array_slice(make_set_if(sourceId, isnotempty(sourceId)), 0, (listedIdsLimit - 1))
, exposurePerimeterScore = dcountif(sourceId, isnotempty(sourceId))
, exposurePerimeterScoreWeighted = sum(sourceWeight)
by targetId
| extend isExposurePerimeterCapped = (exposurePerimeterScore > listedIdsLimit)
);
aggregatedPaths
| top resultCountLimit by exposurePerimeterScore desc
};
connections
| invoke exposure_perimeter_fl(sourceIdColumnName = 'SourceNodeName'
, targetIdColumnName = 'TargetNodeName'
, sourceWeightColumnName = 'SourceNodeVulnerability'
)
输出
targetId | exposurePerimeterList | exposurePerimeterScore | exposurePerimeterScoreWeighted | isExposurePerimeterCapped |
---|---|---|---|---|
hub_router | ["vm-custom","webapp-prd","test-machine"] | 3 | 11 | FALSE |
storage_main_backup | ["vm-work-1","backup_prc"] | 2 | 0 | FALSE |
vm-custom | ["webapp-prd","test-machine"] | 2 | 6 | FALSE |
backup_prc | ["vm-work-2","remote_DT"] | 2 | 3 | FALSE |
webapp-prd | ["vm-work-1","vm-custom"] | 2 | 4 | FALSE |
test-machine | ["webapp-prd"] | 1 | 1 | FALSE |
server-0126 | ["vm-custom"] | 1 | 4 | FALSE |
remote_DT | ["hub_router"] | 1 | 0 | FALSE |
vm-work-2 | ["hub_router"] | 1 | 0 | FALSE |
storage_DevBox | ["backup_prc"] | 1 | 0 | FALSE |
device_A1 | ["sevice_B2"] | 1 | 2 | FALSE |
sevice_B2 | ["device_A1"] | 1 | 1 | FALSE |
运行该函数会获取源和目标之间的连接,并按目标聚合源。 对于每个目标,风险外围将可以连接到它的源表示为分数(常规分数和加权分数)和列表。
输出的每一行包含以下字段:
-
targetId
:从相关列获取的目标节点 ID。 -
exposurePerimeterList
:源节点连接到的目标节点的源节点 ID(从相关列获取)列表。 列表的最大长度限制 listedIdsLimit 参数。 -
exposurePerimeterScore
:分数是可以连接到的目标的源节点计数。 高风险外围分数表示目标节点可能访问大量源,应予以相应处理。 -
exposurePerimeterScoreWeighted
:加权分数是可选源节点权重列的总和,表示其值(例如漏洞或暴露性)。 如果存在此类权重,则由于可能从易受攻击或高度暴露的源进行访问,加权风险外围分数可能是目标节点值的更准确的指标。 -
isExposurePerimeterCapped
:布尔标志,表示源列表是否受 listedIdsLimit 参数限制。 如果受此参数的限制,则除了列出的源之外,还可以访问其他源(最高可达 exposurePerimeterScore 的数量)。
在上面的示例中,我们在源和目标之间的连接基础上运行 graph_exposure_perimeter_fl()
函数。 在输出的第一行中,可以看到目标节点“hub_router”可以从三个源(“vm-custom”、“webapp-prd”、“test-machine”)连接。 我们使用输入数据源 SourceNodeVulnerability 列作为源权重,并得到累积权重 为 11。 此外,由于源数量为 3 且默认列表限制为 50,将显示所有源,所以 isExposurePerimeterCapped 列的值为 FALSE。
如果多跃点路径不可用,可以在源和目标之间构建多跃点路径(例如,运行 “graph_path_discovery_fl()”),并在结果的基础上运行“graph_exposure_perimeter_fl()”。
输出看起来类似,但反映了通过多跃点路径计算的曝光外围,因此是目标节点真实可访问性更好的指标。 为了查找源和目标场景(例如中断)之间的完整路径,graph_path_discovery_fl() 函数可与相关源和目标节点上的筛选器一起使用。
函数 graph_exposure_perimeter_fl()
可用于根据直接边缘或较长的路径计算目标节点的风险外围。 在网络安全域中,该函数可用于获取多个见解。 暴露外围分数(常规和加权),表示目标节点从防御者和攻击者的角度的重要性。 具有高暴露外围(尤其是关键边界)的节点应相应地受到保护。 例如,在访问监视和强化方面。 安全信号(如警报)应优先处理可访问这些节点的源。 应监视暴露外围列表,以查找源和目标之间的意外连接,并在中断方案中使用。 例如,如果某个源存在主动泄露,则应断开它与重要目标之间的连接。