跳转到内容
本站为社区维护的非官方中文翻译,与 Cloudflare, Inc. 无关联。本站不提供账户登录,请勿在任何非官方站点输入您的 Cloudflare 账户信息。官方文档:developers.cloudflare.com

软件包注册表安全

最后更新 查看 MarkdownAgent 设置

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 使用。

Activity Log 字段

以下软件包字段可在 Gateway Activity Log 中使用:

字段 说明
Package Ecosystem 检测到的注册表类型(例如 npm、pypi、cargo)。
Package URL (PURL) 从检测到的坐标派生的 Package URL 字符串(例如 pkg:npm/[email protected])。

Logpush 字段

软件包元数据可在 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 中的依赖项)。

这篇文档对您有帮助吗?