跳转到主要内容

用于扫描Python环境中已知漏洞的工具

项目描述

pip-audit

CI PyPI version Packaging status OpenSSF Scorecard

pip-audit 是一个用于扫描Python环境中存在已知漏洞的包的工具。它通过 PyPI JSON API 使用 Python打包咨询数据库 作为漏洞报告的来源。

本项目部分由 Trail of Bits 维护,并获得 Google 的支持。这不是 Google 或 Trail of Bits 的官方产品。

目录

功能

  • 支持审计本地环境和要求风格文件
  • 支持多个漏洞服务(PyPIOSV
  • 支持以 CycloneDX XML 或 JSON 格式输出 SBOMs
  • 支持自动修复漏洞依赖项(--fix
  • 人类和机器可读的输出格式(列式、Markdown、JSON)
  • 无缝重用现有的本地 pip 缓存

安装

pip-audit 需要 Python 3.8 或更高版本,并且可以直接通过 pip 安装

python -m pip install pip-audit

第三方包

存在多个 第三方pip-audit 包。下面的矩阵和徽章列出了一些

Packaging status Packaging status Conda - Platform Conda (channel only)

特别是,pip-audit 可以通过 conda 安装

conda install -c conda-forge pip-audit

第三方包不直接由本项目支持。有关更详细的安装指南,请参阅您的包管理器文档。

GitHub Actions

pip-audit 有一个官方的 GitHub Action

您可以从 GitHub Marketplace 安装它,或者手动将其添加到您的 CI 中

jobs:
  pip-audit:
    steps:
      - uses: pypa/[email protected]
        with:
          inputs: requirements.txt

有关更多详细信息和使用示例,请参阅 操作文档

pre-commit 支持

pip-audit 支持 pre-commit

例如,使用 pre-commit 通过 pip-audit 审计一个需求文件

  - repo: https://github.com/pypa/pip-audit
    rev: v2.7.3
    hooks:
      -   id: pip-audit
          args: ["-r", "requirements.txt"]

ci:
  # Leave pip-audit to only run locally and not in CI
  # pre-commit.ci does not allow network calls
  skip: [pip-audit]

以下文档中的任何 pip-audit 参数都可以传递。

用法

您可以将 pip-audit 作为独立程序运行,或通过 python -m

pip-audit --help
python -m pip_audit --help
usage: pip-audit [-h] [-V] [-l] [-r REQUIREMENT] [-f FORMAT] [-s SERVICE] [-d]
                 [-S] [--desc [{on,off,auto}]] [--aliases [{on,off,auto}]]
                 [--cache-dir CACHE_DIR] [--progress-spinner {on,off}]
                 [--timeout TIMEOUT] [--path PATH] [-v] [--fix]
                 [--require-hashes] [--index-url INDEX_URL]
                 [--extra-index-url URL] [--skip-editable] [--no-deps]
                 [-o FILE] [--ignore-vuln ID] [--disable-pip]
                 [project_path]

audit the Python environment for dependencies with known vulnerabilities

positional arguments:
  project_path          audit a local Python project at the given path
                        (default: None)

optional arguments:
  -h, --help            show this help message and exit
  -V, --version         show program's version number and exit
  -l, --local           show only results for dependencies in the local
                        environment (default: False)
  -r REQUIREMENT, --requirement REQUIREMENT
                        audit the given requirements file; this option can be
                        used multiple times (default: None)
  -f FORMAT, --format FORMAT
                        the format to emit audit results in (choices: columns,
                        json, cyclonedx-json, cyclonedx-xml, markdown)
                        (default: columns)
  -s SERVICE, --vulnerability-service SERVICE
                        the vulnerability service to audit dependencies
                        against (choices: osv, pypi) (default: pypi)
  -d, --dry-run         without `--fix`: collect all dependencies but do not
                        perform the auditing step; with `--fix`: perform the
                        auditing step but do not perform any fixes (default:
                        False)
  -S, --strict          fail the entire audit if dependency collection fails
                        on any dependency (default: False)
  --desc [{on,off,auto}]
                        include a description for each vulnerability; `auto`
                        defaults to `on` for the `json` format. This flag has
                        no effect on the `cyclonedx-json` or `cyclonedx-xml`
                        formats. (default: auto)
  --aliases [{on,off,auto}]
                        includes alias IDs for each vulnerability; `auto`
                        defaults to `on` for the `json` format. This flag has
                        no effect on the `cyclonedx-json` or `cyclonedx-xml`
                        formats. (default: auto)
  --cache-dir CACHE_DIR
                        the directory to use as an HTTP cache for PyPI; uses
                        the `pip` HTTP cache by default (default: None)
  --progress-spinner {on,off}
                        display a progress spinner (default: on)
  --timeout TIMEOUT     set the socket timeout (default: 15)
  --path PATH           restrict to the specified installation path for
                        auditing packages; this option can be used multiple
                        times (default: [])
  -v, --verbose         run with additional debug logging; supply multiple
                        times to increase verbosity (default: 0)
  --fix                 automatically upgrade dependencies with known
                        vulnerabilities (default: False)
  --require-hashes      require a hash to check each requirement against, for
                        repeatable audits; this option is implied when any
                        package in a requirements file has a `--hash` option.
                        (default: False)
  --index-url INDEX_URL
                        base URL of the Python Package Index; this should
                        point to a repository compliant with PEP 503 (the
                        simple repository API); this will be resolved by pip
                        if not specified (default: None)
  --extra-index-url URL
                        extra URLs of package indexes to use in addition to
                        `--index-url`; should follow the same rules as
                        `--index-url` (default: [])
  --skip-editable       don't audit packages that are marked as editable
                        (default: False)
  --no-deps             don't perform any dependency resolution; requires all
                        requirements are pinned to an exact version (default:
                        False)
  -o FILE, --output FILE
                        output results to the given file (default: stdout)
  --ignore-vuln ID      ignore a specific vulnerability by its vulnerability
                        ID; this option can be used multiple times (default:
                        [])
  --disable-pip         don't use `pip` for dependency resolution; this can
                        only be used with hashed requirements files or if the
                        `--no-deps` flag has been provided (default: False)

退出代码

完成时,pip-audit 将退出并返回表示其状态的代码。

当前的代码是

  • 0:未检测到已知漏洞。
  • 1:发现一个或多个已知漏洞。

pip-audit 的退出代码不能被抑制。有关支持的替代方案,请参阅 抑制 pip-audit 的退出代码

模拟运行

pip-audit 支持使用 --dry-run 标志来控制是否实际执行审计(或修复)步骤。

  • 单独使用 pip-audit --dry-run 时,将跳过审计步骤并打印出将要审计的依赖项数量。
  • 在修复模式下,使用 pip-audit --fix --dry-run 执行审计步骤并打印出将要执行的修复行为(即哪些依赖项将被升级或跳过)。

示例

审计当前 Python 环境的依赖项

$ pip-audit
No known vulnerabilities found

审计给定需求文件的依赖项

$ pip-audit -r ./requirements.txt
No known vulnerabilities found

审计需求文件的依赖项,排除系统包

$ pip-audit -r ./requirements.txt -l
No known vulnerabilities found

审计本地 Python 项目的依赖项

$ pip-audit .
No known vulnerabilities found

pip-audit 在提供的路径中搜索各种 Python "项目" 文件。目前仅支持 pyproject.toml

存在漏洞时审计依赖项

$ pip-audit
Found 2 known vulnerabilities in 1 package
Name  Version ID             Fix Versions
----  ------- -------------- ------------
Flask 0.5     PYSEC-2019-179 1.0
Flask 0.5     PYSEC-2018-66  0.12.3

审计包括别名的依赖项

$ pip-audit --aliases
Found 2 known vulnerabilities in 1 package
Name  Version ID             Fix Versions Aliases
----  ------- -------------- ------------ -------------------------------------
Flask 0.5     PYSEC-2019-179 1.0          CVE-2019-1010083, GHSA-5wv5-4vpf-pj6m
Flask 0.5     PYSEC-2018-66  0.12.3       CVE-2018-1000656, GHSA-562c-5r94-xh97

审计包括描述的依赖项

$ pip-audit --desc
Found 2 known vulnerabilities in 1 package
Name  Version ID             Fix Versions Description
----  ------- -------------- ------------ --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Flask 0.5     PYSEC-2019-179 1.0          The Pallets Project Flask before 1.0 is affected by: unexpected memory usage. The impact is: denial of service. The attack vector is: crafted encoded JSON data. The fixed version is: 1. NOTE: this may overlap CVE-2018-1000656.
Flask 0.5     PYSEC-2018-66  0.12.3       The Pallets Project flask version Before 0.12.3 contains a CWE-20: Improper Input Validation vulnerability in flask that can result in Large amount of memory usage possibly leading to denial of service. This attack appear to be exploitable via Attacker provides JSON data in incorrect encoding. This vulnerability appears to have been fixed in 0.12.3. NOTE: this may overlap CVE-2019-1010083.

以 JSON 格式审计依赖项

$ pip-audit -f json | python -m json.tool
Found 2 known vulnerabilities in 1 package
[
  {
    "name": "flask",
    "version": "0.5",
    "vulns": [
      {
        "id": "PYSEC-2019-179",
        "fix_versions": [
          "1.0"
        ],
        "aliases": [
          "CVE-2019-1010083",
          "GHSA-5wv5-4vpf-pj6m"
        ],
        "description": "The Pallets Project Flask before 1.0 is affected by: unexpected memory usage. The impact is: denial of service. The attack vector is: crafted encoded JSON data. The fixed version is: 1. NOTE: this may overlap CVE-2018-1000656."
      },
      {
        "id": "PYSEC-2018-66",
        "fix_versions": [
          "0.12.3"
        ],
        "aliases": [
          "CVE-2018-1000656",
          "GHSA-562c-5r94-xh97"
        ],
        "description": "The Pallets Project flask version Before 0.12.3 contains a CWE-20: Improper Input Validation vulnerability in flask that can result in Large amount of memory usage possibly leading to denial of service. This attack appear to be exploitable via Attacker provides JSON data in incorrect encoding. This vulnerability appears to have been fixed in 0.12.3. NOTE: this may overlap CVE-2019-1010083."
      }
    ]
  },
  {
    "name": "jinja2",
    "version": "3.0.2",
    "vulns": []
  },
  {
    "name": "pip",
    "version": "21.3.1",
    "vulns": []
  },
  {
    "name": "setuptools",
    "version": "57.4.0",
    "vulns": []
  },
  {
    "name": "werkzeug",
    "version": "2.0.2",
    "vulns": []
  },
  {
    "name": "markupsafe",
    "version": "2.0.1",
    "vulns": []
  }
]

审计并尝试自动升级漏洞依赖项

$ pip-audit --fix
Found 2 known vulnerabilities in 1 package and fixed 2 vulnerabilities in 1 package
Name  Version ID             Fix Versions Applied Fix
----- ------- -------------- ------------ ----------------------------------------
flask 0.5     PYSEC-2019-179 1.0          Successfully upgraded flask (0.5 => 1.0)
flask 0.5     PYSEC-2018-66  0.12.3       Successfully upgraded flask (0.5 => 1.0)

故障排除

您是否解决了 pip-audit 的问题?通过为此部分做出贡献来帮助我们!

pip-audit 显示了无关的漏洞报告!

在一个完美的世界里,漏洞信息源将具有无限的信号与噪声比:每一个漏洞报告都会(1)正确,并且(2)适用于每个依赖项的每一种使用。

不幸的是,这两者都无法保证:漏洞信息源不会免疫于无关或垃圾邮件报告,并且并不是所有特定依赖项的使用都映射到所有潜在类型的漏洞。

如果你的pip-audit运行产生的漏洞报告对你的特定应用或用例没有可操作性的话,你可以使用--ignore-vuln ID选项来忽略特定的漏洞报告。--ignore-vuln支持别名,因此如果你要忽略的报告没有PYSEC ID,你可以使用GHSA-xxxCVE-xxx ID代替PYSEC-xxx ID。

例如,以下是如何忽略GHSA-w596-4wvx-j9j6的方法,它是pytest用户常见的高噪声漏洞报告和误报来源,pytest的GitHub链接:pytest

# Run the audit as normal, but exclude any reports that match GHSA-w596-4wvx-j9j6
$ pip-audit --ignore-vuln GHSA-w596-4wvx-j9j6

--ignore-vuln ID选项与所有其他依赖项解析和审计选项兼容,这意味着它应该与以requirements风格输入、替代漏洞信息源等方式正确工作。

它可以多次传递,以忽略多个报告

# Run the audit as normal, but exclude any reports that match these IDs
$ pip-audit --ignore-vuln CVE-XXX-YYYY --ignore-vuln CVE-ZZZ-AAAA

pip-audit运行时间比预期的要长!

根据你如何使用它,pip-audit可能需要执行自己的依赖项解析,这可能需要的时间大约与pip install对项目执行的时间相当。请参阅安全模型以了解解释。

你有两种避免依赖项解析的方法:审计预先安装的环境,或确保你的依赖项已经完全解析

如果你知道你已经完全配置了一个与pip-audit -r requirements.txt审计相同的环境,你可以简单地重用它

# Note the absence of any "input" arguments, indicating that the environment is used.
$ pip-audit

# Optionally filter out non-local packages, for virtual environments:
$ pip-audit --local

或者,如果你的输入已经完全锁定(可选地包含哈希),你可以告诉pip-audit跳过依赖项解析,使用--no-deps(未使用哈希锁定)或--require-hashes(包含哈希锁定)。

后者等同于pip哈希检查模式,并且更受推荐,因为它提供了额外的完整性。

# fails if any dependency is not fully pinned
$ pip-audit --no-deps -r requirements.txt

# fails if any dependency is not fully pinned *or* is missing hashes
$ pip-audit --require-hashes -r requirements.txt

pip-audit无法对我的第三方索引进行身份验证!

经过身份验证的第三方或私有索引

pip-audit支持--index-url--extra-index-url来配置替代或补充包索引,就像pip一样。

当未经过身份验证时,这些索引应该按预期工作。但是,当第三方索引需要身份验证时,pip-audit在普通pip之上还有一些额外的限制

  • 交互式身份验证不支持。换句话说:pip-audit不会提示你输入索引的凭据。
  • pipkeyring身份验证是支持的,但仅限于有限的方式:pip-audit使用subprocess keyring提供程序,因为审计发生在隔离的虚拟环境中。subprocess提供程序反过来又受到额外的限制(如必需的用户名);pip的文档详细解释了这些。

除此之外,一些第三方索引有必需的、硬编码的用户名。例如,对于Google Artifact registry,硬编码的用户名是oauth2accesstoken。请参阅#742pip#11971以获取更多信息。

技巧和窍门

针对pipenv项目进行运行

pipenv 使用 PipfilePipfile.lock 文件来跟踪和冻结依赖项,而不是使用 requirements.txt 文件。然而,pip-audit 无法直接处理 Pipfile[.lock] 文件,但可以将这些文件转换为 pip-audit 可以运行的受支持的 requirements.txt 文件。自 v2022.4.8 起开始,pipenv 内置了将依赖项转换为 requirements.txt 文件的命令。

$ pipenv run pip-audit -r <(pipenv requirements)

抑制 pip-audit 的退出码

pip-audit 故意不支持内部抑制其自己的退出码。

需要抑制失败的 pip-audit 调用的用户可以使用标准的shell惯用语来做到这一点

pip-audit || true

或者,要完全退出

pip-audit || exit 0

退出码也可以被捕获并显式处理

pip-audit
exitcode="${?}"
# do something with ${exitcode}

有关需要处理的潜在代码列表,请参阅退出码

仅报告可修复的漏洞

在开发工作流程中,您可能希望忽略尚未修复的漏洞,并在发布过程中进行调查。pip-audit 不支持忽略未修复的漏洞。但是,您可以将其输出导出为JSON格式,并对其进行外部处理。例如,如果您想仅在检测到有已知修复版本的漏洞时退出非零代码,您可以使用 jq 进行处理:

test -z "$(pip-audit -r requirements.txt --format=json 2>/dev/null | jq '.dependencies[].vulns[].fix_versions[]')"

使用此方法的简单(且效率低下)的示例是

test -z "$(pip-audit -r requirements.txt --format=json 2>/dev/null | jq '.dependencies[].vulns[].fix_versions[]')" || pip-audit -r requirements.txt

它像往常一样运行 pip-audit,并且仅在已知漏洞有修复版本时才退出非零代码。

安全模型

本节旨在描述使用 pip-audit 时您可以和必须不做的安全假设。

TL;DR:如果您不会使用 pip install 它,那么您也不应该使用 pip audit 它。

pip-audit 是一个用于审计Python环境中具有已知漏洞的包的工具。“已知漏洞”是指包中的公开报告的错误,如果未纠正,可能会允许恶意行为者执行未预期的操作。

pip-audit 可以通过告诉您何时拥有它们以及如何升级它们来保护您免受已知漏洞的侵害。例如,如果您的环境中包含 somepackage==1.2.3,则 pip-audit 可以告诉您它需要升级到 1.2.4

您可以假设 pip-audit 将尽力解决所有Python依赖项,并且要么完全审计每个依赖项,要么明确声明它跳过了哪些依赖项以及为什么跳过它们。

pip-audit 不是一个静态代码分析器。它分析依赖项树,而不是代码,并且无法保证静态地发生任意的依赖项解析。要了解为什么是这样,请参阅Dustin Ingram的关于Python中依赖项解析的优秀帖子

因此:您绝对不应该假设 pip-audit 会保护您免受恶意包的侵害。特别是,将 pip-audit -r INPUT 作为 pip-audit 的“更安全”变体是不正确的。从所有目的和意义上讲,pip-audit -r INPUT 功能上等同于 pip install -r INPUT,并且具有少量非安全隔离,以避免与任何本地环境冲突。

pip-audit 主要是用于Python包的审计工具。您绝对不应该假设 pip-audit 会检测或标记通过Python包暴露的“传递”漏洞,而这些漏洞实际上并非包本身的一部分。例如,pip-audit 的漏洞信息来源不太可能包括对可能被流行的Python包使用的有漏洞的共享库的警告,因为Python包的版本与共享库的版本没有紧密的联系。

许可

pip-audit 采用 Apache 2.0 许可协议。

pip-audit 重用并修改了来自 resolvelib 的示例,该示例采用 ISC 许可协议。

贡献

有关详细信息,请参阅 贡献文档

行为准则

与该项目互动的所有人应遵守 PSF 行为准则

项目详情


发行历史 发行通知 | RSS 源

下载文件

下载适用于您平台文件。如果您不确定选择哪个,请了解有关 安装软件包 的更多信息。

源代码分发

pip_audit-2.7.3.tar.gz (50.4 kB 查看散列值)

上传时间 源代码

构建分发

pip_audit-2.7.3-py3-none-any.whl (56.3 kB 查看散列值)

上传时间 Python 3

由以下支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面