Gateway 可以检测七种主要软件包生态系统中的软件包下载,并让你对供应链流量进行策略控制。当开发人员或 CI/CD 流水线通过 Gateway 下载软件包时,代理会从请求 URL 识别注册表协议,并提取软件包生态系统、名称、版本和命名空间。然后你可以使用 pkg.* 选择器编写 HTTP 策略,按所需粒度允许或拦截软件包下载,从拦截整个生态系统到限制单个软件包版本。
软件包检测完全基于 HTTP 请求 URL 结构运行。Gateway 识别每个受支持注册表协议的 API 约定,而不是提供流量的主机名。这意味着无论流量发往官方公共注册表、自托管镜像、Artifactory 或 Nexus 等企业代理注册表,还是任何其他兼容端点,检测方式都相同。如果 URL 路径匹配已知注册表下载的形态,Gateway 就会对其进行分类。
检测是 fail-open 的。如果 URL 无法被分类为软件包下载,请求会作为普通非软件包流量继续。分类失败永远不会拦截或中断软件包安装。
Gateway 检测以下生态系统的软件包下载:
| 生态系统 | 示例构件模式 | 命名空间 |
|---|---|---|
| npm | /{package}/-/{package}-{version}.tgz |
Scope(例如 @babel) |
| PyPI | /packages/{hash}/{hash}/{hash}/{package}-{version}.whl |
— |
| RubyGems | /gems/{package}-{version}.gem |
— |
| Cargo | /crates/{package}/{package}-{version}.crate |
— |
| Go | /{module}/@v/{version}.zip |
模块路径 |
| Maven | /maven2/{group}/{artifact}/{version}/{artifact}-{version}.jar |
Group ID |
| NuGet | /{package}/{version}/{package}.{version}.nupkg |
— |
初始版本仅检测 download(下载) 操作。下载是在每个受支持注册表中都能从 URL 路径推导出软件包名称、版本和生态系统的唯一操作。resolve(元数据查找)和 publish 等其他操作使用不同的端点、主机或 HTTP 方法,需要 URL 路径之外的额外信号。
以下选择器可用于带有 Allow 和 Block 操作的 HTTP 策略:
| 选择器 | UI 名称 | API 示例 | 说明 |
|---|---|---|---|
pkg.ecosystem |
Package Ecosystem | pkg.ecosystem == "npm" |
从请求 URL 检测到的软件包生态系统。 |
pkg.name |
Package Name | pkg.name == "lodash" |
从下载 URL 提取的软件包名称。 |
pkg.version |
Package Version | pkg.version == "4.17.21" |
从下载 URL 提取的软件包版本。支持精确匹配和感知生态系统的比较运算符。 |
pkg.namespace |
Package Namespace | pkg.namespace == "@babel" |
软件包命名空间(当生态系统支持时)。对于 npm 这是 scope,对于 Maven 这是 group ID,对于 Go 这是模块路径。 |
pkg.purl |
Package URL | pkg.purl == "pkg:npm/[email protected]" |
从检测到的坐标派生的 Package URL (PURL) ↗。仅在 API 中可用。 |
在仪表板中,Package Ecosystem(软件包生态系统) 是主选择器。选择它会显示用于指定软件包名称、版本和命名空间的嵌套字段。适用以下规则:
- 必须先选择生态系统,其他软件包字段才会可用。
- 必须恰好选择一个生态系统才能启用嵌套字段。如果使用
in或not in运算符匹配多个生态系统,嵌套的软件包名称、版本和命名空间字段会被禁用。 - 必须先添加软件包名称,才能添加版本约束。
- 命名空间字段仅适用于支持命名空间的生态系统。标签会根据所选生态系统变化:npm 为 Scope,Maven 为 Group ID,Go 为 Module namespace。
pkg.purl(Package URL)选择器在仪表板中不可用。请使用 API 编写匹配 PURL 的表达式。
直接使用 API 时,这些选择器可以在 wirefilter 表达式中自由组合,不受这些约束。
除精确字符串匹配外,pkg.version 选择器还支持感知生态系统的比较运算符。每个生态系统使用其原生版本语义:
| 生态系统 | 版本标准 |
|---|---|
| npm | SemVer |
| Cargo | SemVer |
| PyPI | PEP 440 |
| RubyGems | Gem::Version |
| Go | Go module versions |
| Maven | Maven version ordering |
| NuGet | NuGet normalization and ordering |
支持以下比较运算符:
| 运算符 | API 语法 | 说明 |
|---|---|---|
| equals(等于) | == |
使用生态系统特定身份规则的规范化相等。 |
| not equals(不等于) | != |
规范化相等的否定。 |
| greater than(大于) | > |
使用原生排序,版本大于指定值。 |
| greater than or equal(大于或等于) | >= |
版本大于或等于指定值。 |
| less than(小于) | < |
版本小于指定值。 |
| less than or equal(小于或等于) | <= |
版本小于或等于指定值。 |
当版本字符串无法按生态系统的版本规则解析,或检测到的生态系统与比较上下文不匹配时,比较不产生匹配。这包括 !=,意味着无法解析的版本不会匹配任何内容。
要在整个组织中拦截所有 PyPI 软件包下载:
| 选择器 | 运算符 | 值 | 操作 |
|---|---|---|---|
| Package Ecosystem | is(是) | pypi |
Block(拦截) |
Wirefilter 表达式:
pkg.ecosystem == "pypi"要拦截已知恶意或不需要的 npm 软件包,无论版本如何:
| 选择器 | 运算符 | 值 | 逻辑 | 操作 |
|---|---|---|---|---|
| Package Ecosystem | is(是) | npm |
And(且) | Block(拦截) |
| Package Name | is(是) | event-stream |
Wirefilter 表达式:
pkg.ecosystem == "npm" and pkg.name == "event-stream"要拦截低于 4.17.21 的所有 lodash 版本(该版本修复了 CVE-2021-23337):
| 选择器 | 运算符 | 值 | 逻辑 | 操作 |
|---|---|---|---|---|
| Package Ecosystem | is(是) | npm |
And(且) | Block(拦截) |
| Package Name | is(是) | lodash |
And(且) | |
| Package Version | less than(小于) | 4.17.21 |
Wirefilter 表达式:
pkg.ecosystem == "npm" and pkg.name == "lodash" and pkg.version < "4.17.21"要仅通过企业 Artifactory 实例允许 npm 软件包下载并拦截所有其他 npm 下载,请创建两条策略:
策略 1 - 允许核准镜像(更高优先级):
| 选择器 | 运算符 | 值 | 逻辑 | 操作 |
|---|---|---|---|---|
| Package Ecosystem | is(是) | npm |
And(且) | Allow(允许) |
| Host | is(是) | npm.internal.example.com |
Wirefilter 表达式:
pkg.ecosystem == "npm" and http.request.host == "npm.internal.example.com"策略 2 - 拦截所有其他 npm 下载(更低优先级):
| 选择器 | 运算符 | 值 | 操作 |
|---|---|---|---|
| Package Ecosystem | is(是) | npm |
Block(拦截) |
Wirefilter 表达式:
pkg.ecosystem == "npm"因为检测基于注册表协议而不是主机名,公共 registry.npmjs.org 和位于 npm.internal.example.com 的内部镜像都会被检测为 npm 流量。策略 1(更高优先级)允许核准镜像,策略 2 拦截其他所有内容。
要仅通过企业注册表允许下载敏感内部软件包,并拦截来自所有其他来源的下载:
策略 1 - 允许来自核准主机(更高优先级):
| 选择器 | 运算符 | 值 | 逻辑 | 操作 |
|---|---|---|---|---|
| Package Ecosystem | is(是) | npm |
And(且) | Allow(允许) |
| Package Namespace | is(是) | @acme |
And(且) | |
| Package Name | is(是) | internal-sdk |
And(且) | |
| Host | is(是) | npm.internal.example.com |
Wirefilter 表达式:
pkg.ecosystem == "npm" and pkg.namespace == "@acme" and pkg.name == "internal-sdk" and http.request.host == "npm.internal.example.com"策略 2 - 拦截来自所有其他主机(更低优先级):
| 选择器 | 运算符 | 值 | 逻辑 | 操作 |
|---|---|---|---|---|
| Package Ecosystem | is(是) | npm |
And(且) | Block(拦截) |
| Package Namespace | is(是) | @acme |
And(且) | |
| Package Name | is(是) | internal-sdk |
Wirefilter 表达式:
pkg.ecosystem == "npm" and pkg.namespace == "@acme" and pkg.name == "internal-sdk"软件包检测根据每个注册表下载 API 的 URL 路径结构对流量进行分类。它不依赖匹配已知注册表主机名列表。此设计意味着,任何使用兼容 URL 布局提供软件包的服务器都会以相同方式被检测,无论它是:
- 官方公共注册表(例如
registry.npmjs.org或pypi.org) - JFrog Artifactory、Sonatype Nexus 或 AWS CodeArtifact 等企业代理注册表
- 自托管镜像
- CDN 前置的注册表端点
http.request.host 选择器仍可用于需要区分特定注册表主机的策略。通过将 pkg.* 选择器与 http.request.host 组合,你可以编写根据软件包获取来源应用不同操作的规则。
当 Gateway 检测到软件包下载时,软件包元数据会包含在 Gateway HTTP 日志中。此数据可在 Gateway 活动日志中使用,也可通过 Logpush 使用。
以下软件包字段可在 Gateway Activity Log 中使用:
| 字段 | 说明 |
|---|---|
| Package Ecosystem | 检测到的注册表类型(例如 npm、pypi、cargo)。 |
| Package URL (PURL) | 从检测到的坐标派生的 Package URL 字符串(例如 pkg:npm/[email protected])。 |
软件包元数据可在 gateway_http Logpush 数据集的 PackageInfo 对象中使用:
| 字段 | 类型 | 说明 |
|---|---|---|
PackageInfo.Ecosystem |
string |
检测到的软件包生态系统。 |
PackageInfo.Namespace |
string |
软件包命名空间(如适用)。 |
PackageInfo.Name |
string |
软件包名称。 |
PackageInfo.Version |
string |
软件包版本字符串。 |
PackageInfo.Purl |
string |
Package URL 字符串。 |
- 软件包检测要求开启 TLS 解密。通过绕过 TLS 检查的连接下载的软件包(由于 Do Not Inspect 策略或检查限制列表上的应用程序)不会被检测。
- 某些语言运行时和 HTTP 客户端维护独立于操作系统的证书信任存储。如果用于检查的证书(例如 Cloudflare 托管证书)仅安装在操作系统信任存储中,这些客户端的软件包下载可能因证书验证错误而失败。有关将证书添加到应用程序特定信任存储的说明(包括 Python、Node.js、Ruby、Rust、Java 和 Go),请参阅手动安装证书。
- 仅检测 download(下载) 操作。元数据查找(resolve)、软件包发布和其他注册表操作不会被分类。
- 版本比较使用每个生态系统的原生排序规则。不支持跨生态系统的版本比较。
- 不支持生态系统特定的范围语法(例如 npm
^1.2.3、PyPI~=1.4或 Maven interval notation)。请改用单独的比较运算符(>、<、>=、<=)。 - 不支持检测软件包归档中的依赖软件包(例如 shaded 或 fat JAR 中的依赖项)。