llnl/Surfactant

GitHub: llnl/Surfactant

一个基于 Python 的模块化框架,用于从文件元数据生成 SBOM 并进行依赖关系分析。

Stars: 40 | Forks: 23

Blue magnifying glass Surfactant logo

# 表面活性剂 一个用于收集文件信息以生成软件物料清单(SBOM)和依赖分析的模块化框架。 [![CI Test Status](https://static.pigsec.cn/wp-content/uploads/repos/2026/04/421757aeba050640.svg)](https://github.com/LLNL/Surfactant/actions/workflows/pytest.yml) [![PyPI](https://img.shields.io/pypi/v/surfactant)](https://pypi.org/project/Surfactant/) [![Python Versions](https://img.shields.io/pypi/pyversions/surfactant.svg)](https://pypi.org/project/Surfactant/) [![MIT License](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/LLNL/Surfactant/blob/main/LICENSE) [![Documentation Status](https://readthedocs.org/projects/surfactant/badge/?version=latest)](https://surfactant.readthedocs.io/en/latest/?badge=latest) [![pre-commit.ci status](https://results.pre-commit.ci/badge/github/LLNL/Surfactant/main.svg)](https://results.pre-commit.ci/latest/github/LLNL/Surfactant/main) [Documentation](https://surfactant.readthedocs.io/en/latest/) ## 说明 Surfactant 可用于从一组文件中收集信息以生成 SBOM,并能够对 SBOM 进行操作和分析其中的信息。它从与解压后的软件包相对应的目录结构中包含的文件类型(如 PE、ELF 或 MSI 文件)中提取信息。默认情况下,这些信息是文件中不要求运行文件或反编译即可获得的“表面级”元数据。 ## 安装 ### 对于用户: 为了方便使用,我们推荐使用 [pipx](https://github.com/pypa/pipx),因为它能透明地创建和使用 Python 虚拟环境,有助于避免与其他已安装的 Python 应用产生依赖冲突。请按照 [安装说明](https://github.com/pypa/pipx#install-pipx) 安装 `pipx`。 1. 使用 `pipx install` 安装 Surfactant(需要 python >= 3.10) ``` pipx install surfactant ``` 2. 使用 `pipx inject surfactant` 安装插件。例如,这是从 Git 仓库安装模糊哈希插件的方式(也可使用 PyPI 包名、本地源目录或 wheel 文件)。 ``` pipx inject surfactant git+https://github.com/LLNL/Surfactant#subdirectory=plugins/fuzzyhashes ``` 如果出于某种原因需要手动管理虚拟环境,可以使用以下步骤替代: 1. 使用 python >= 3.10 创建并激活虚拟环境 [可选,但强烈建议替代全局安装] ``` python -m venv venv source venv/bin/activate ``` 2. 使用 `pip install` 安装 Surfactant ``` pip install surfactant ``` 3. 使用 `pip install` 安装插件。例如,这是从 Git 仓库安装模糊哈希插件的方式(也可使用 PyPI 包名、本地源目录或 wheel 文件)。 ``` pip install git+https://github.com/LLNL/Surfactant#subdirectory=plugins/fuzzyhashes ``` ### 对于开发者: 1. 使用 python >= 3.10 创建虚拟环境 [可选,但推荐] ``` python -m venv venv source venv/bin/activate ``` 2. 克隆 sbom-surfactant ``` git clone git@github.com:LLNL/Surfactant.git ``` 3. 创建一个可编辑的 Surfactant 安装(代码更改会立即生效): ``` pip install -e . ``` 要安装运行 pytest 和 pre-commit 所需的依赖项: ``` pip install -e ".[test,dev]" ``` 也可以使用 `-e` 或 `--editable` 选项运行 `pip install` 来安装 Surfactant 插件用于开发。 ## 快速入门:生成 SBOM Surfactant 支持多个子命令,可通过 `surfactant --help` 查看。主要用于创建 SBOM 的子命令是 `generate`,它接受以下参数: ``` surfactant generate [OPTIONS] SPECIMEN_CONTEXT SBOM_OUTFILE [INPUT_SBOM] ``` 两个必需参数是样本上下文和输出的 SBOM 文件名。对于为单个目录或文件生成 SBOM 的简单情况,只需使用该目录或文件的路径作为样本配置即可。例如,以下命令将生成一个名为 `output.json` 的 SBOM 文件,其中包含 `mysoftware` 文件夹中找到的所有文件的软件条目: ``` surfactant generate /usr/local/mysoftware output.json ``` 在生成的 SBOM 中,每个文件都会对应一个软件条目。捕获的安装路径将显示文件在 `/usr/local/mysoftware` 中的位置——如果给出的是相对路径,如 `surfactant generate local/mysoftware output.json`,则所有文件的安装路径都会显示在相对路径 `local/mysoftware` 下,而不是绝对路径。 如需对用于创建软件条目和关系的选项进行更精细的控制,或从多个目录收集信息,请参阅以下关于如何编写 [Surfactant 样本上下文文件](#build-context-file-for-sample) 的说明。该上下文文件是一个 JSON 文件,随后可以将其作为 `SPECIMEN_CONTEXT` 参数提供给 Surfactant。 注意:当使用 Surfactant 样本上下文 JSON 文件时,建议其以 `.json` 扩展名结尾;否则,你必须使用特殊前缀(`context:`)来告知 Surfactant,该参数对应的文件不以 `.json` 结尾,应被解释为样本配置而非仅包含单个文件详细信息的 SBOM。 ## 设置 可以通过 `surfactant config` 子命令或手动编辑设置配置文件来更改 Surfactant 设置(这与用于特定样本的 JSON 配置文件不同)。[设置文档页面](https://surfactant.readthedocs.io/en/latest/settings.html) 列出了 Surfactant 内置的可用选项。 ### 命令行 使用 `surfactant config` 与 `git config` 的基本用法非常相似。要设置的键的格式为 `section.option`,其中 `section` 通常是插件名称或 `core`,而 `option` 是要设置的选项。例如,可以使用 `core.recorded_institution` 选项来配置生成 SBOM 时记录的机构。 可以通过以下命令将该选项设置为 `LLNL`: ``` surfactant config core.recorded_institution LLNL ``` 要获取该选项的当前设置值,可以执行: ``` surfactant config core.recorded_institution ``` 另一个你可能想要更改的设置是 `docker.enable_docker_scout`,它控制是否启用 Docker Scout。要禁用 Docker Scout(同时也会抑制关于安装 Docker Scout 的警告信息),请将该选项设置为 `false`: ``` surfactant config docker.enable_docker_scout false ``` ### 手动编辑 如果需要,设置配置文件也可以手动编辑。该文件的位置取决于你的平台。 在 Unix 类平台(包括 macOS)上,遵循 XDG 目录规范,设置将存储在: `${XDG_CONFIG_HOME}/surfactant/config.toml`。如果未设置 `XDG_CONFIG_HOME` 环境变量,则默认位置为 `~/.config`。在 Windows 上,该文件存储在漫游的 AppData 文件夹中,路径为 `%APPDATA%\\surfactant\\config.toml`。 该文件本身是一个 TOML 文件,对于前面提到的示例插件,其内容可能如下所示: ``` [core] recorded_institution = "LLNL" ``` ## 用法 ### 识别样本文件 为了测试 Surfactant,你需要一个样本文件或文件夹来生成 SBOM。如果没有现成的文件,可以从以下地址下载并使用便携的 .zip 文件: 或 Linux 的 .tar.gz 文件:。 ### 构建样本的上下文文件 样本的 JSON 上下文文件包含要收集信息的样本信息。该仓库的 examples 文件夹中可以找到示例 JSON 上下文文件。 - **extractPaths**:(必需)从当前工作目录到要收集信息的文件或文件夹的绝对路径或相对路径。请注意,即使在 Windows 上,也应使用 Unix 风格的 `/` 目录分隔符。 - **archive**:(可选)包含 `extractPaths` 中文件或文件夹的 zip、安装程序或其他归档文件的完整路径(包括文件名)。这将用于收集整个样本的元数据,并作为“Contains”关系添加到所有找到的软件条目中。 - **installPrefix**:(可选)文件在系统中正确安装后的位置,例如 “C:/”、”C:/Program Files/” 等。请注意,即使在 Windows 上,也应使用 Unix 风格的 `/` 目录分隔符。如果未提供,则 `extractPaths` 将用作安装前缀。 - **omitUnrecognizedTypes**:(可选)如果设为 True,则忽略未识别的文件类型。 - **includeFileExts**:(可选)要包含的文件扩展名列表,即使未被 Surfactant 识别。当 `omitUnrecognizedTypes` 设为 True 时此选项才有效。 - **excludeFileExts**:(可选)要排除的文件扩展名列表,即使被 Surfactant 识别。请注意,如果同时设置了 `omitUnrecognizedTypes` 和 `includeFileExts`,则 `includeFileExts` 中指定的扩展名仍会被包含。 - **skipProcessingArchive**:(可选)跳过对给定归档文件的信息提取器处理。仅包含归档文件的基本信息(如哈希值)。默认设置为 False。 #### 使用 TUI 创建上下文文件 Surfactant 的 TUI 有一个“Context”标签,可用于创建上下文文件。运行 `surfactant tui` 启动 TUI,然后导航到该标签页以进入编辑器创建和修改上下文文件。这是新用户从头创建上下文文件的最简便方式章节将展示上下文文件的外观以及在不同选项设置下生成的 SBOM 结果。 #### 示例上下文文件 假设你有一个 .tar.gz 文件要运行 Surfactant。以 HELICS 发布的 .tar.gz 文件为例。在此场景中,该文件的绝对路径为 `/home/samples/helics.tar.gz`。解压该文件后,会得到一个包含 bin、include、lib64 和 share 四个子文件夹的 helics 文件夹。 ##### 示例 1:简单上下文文件 如果只想包含包含二进制文件的文件夹以进行分析,最基础的上下文文件如下: ``` [ { "extractPaths": ["/home/samples/helics/bin", "/home/samples/helics/lib64"] } ] ``` 生成的 SBOM 结构如下: ``` { "software": [ { "UUID": "abc1", "fileName": ["helics_binary"], "installPath": ["/home/samples/helics/bin/helics_binary"], "containerPath": null }, { "UUID": "abc2", "fileName": ["lib1.so"], "installPath": ["/home/samples/helics/lib64/lib1.so"], "containerPath": null } ], "relationships": [ { "xUUID": "abc1", "yUUID": "abc2", "relationship": "Uses" } ] } ``` ##### 示例 2:详细上下文文件 更详细的上下文文件可能如下所示。生成的 SBOM 将包含一个 helics.tar.gz 的软件条目,并带有“Contains”关系到 extractPaths 中找到的所有二进制文件。提供 `/` 作为 installPrefix 以及 `/home/samples/helics` 作为 extractPaths,将使 Surfactant 正确地为子文件夹中的二进制文件分配 SBOM 中的安装路径 `/bin` 和 `/lib64`。 ``` [ { "archive": "/home/samples/helics.tar.gz", "extractPaths": ["/home/samples/helics"], "installPrefix": "/" } ] ``` 生成的 SBOM 结构如下: ``` { "software": [ { "UUID": "abc0", "fileName": ["helics.tar.gz"], "installPath": null, "containerPath": null }, { "UUID": "abc1", "fileName": ["helics_binary"], "installPath": ["/bin/helics_binary"], "containerPath": ["abc0/bin/helics_binary"] }, { "UUID": "abc2", "fileName": ["lib1.so"], "installPath": ["/lib64/lib1.so"], "containerPath": ["abc0/lib64/lib1.so"] } ], "relationships": [ { "xUUID": "abc0", "yUUID": "abc1", "relationship": "Contains" }, { "xUUID": "abc0", "yUUID": "abc2", "relationship": "Contains" }, { "xUUID": "abc1", "yUUID": "abc2", "relationship": "Uses" } ] } ``` ##### 示例 3:添加相关二进制文件 如果我们的 helics tar.gz 文件附带一个相关的 tar.gz 文件,用于安装插件扩展模块(解压到包含 bin 和 lib64 子文件夹的 helics_plugin 文件夹),我们也可以在上下文文件中添加这些信息: ``` [ { "archive": "/home/samples/helics.tar.gz", "extractPaths": ["/home/samples/helics"], "installPrefix": "/" }, { "archive": "/home/samples/helics_plugin.tar.gz", "extractPaths": ["/home/samples/helics_plugin"], "installPrefix": "/" } ] ``` 生成的 SBOM 结构如下: ``` { "software": [ { "UUID": "abc0", "fileName": ["helics.tar.gz"], "installPath": null, "containerPath": null }, { "UUID": "abc1", "fileName": ["helics_binary"], "installPath": ["/bin/helics_binary"], "containerPath": ["abc0/bin/helics_binary"] }, { "UUID": "abc2", "fileName": ["lib1.so"], "installPath": ["/lib64/lib1.so"], "containerPath": ["abc0/lib64/lib1.so"] }, { "UUID": "abc3", "fileName": ["helics_plugin.tar.gz"], "installPath": null, "containerPath": null }, { "UUID": "abc4", "fileName": ["helics_plugin"], "installPath": ["/bin/helics_plugin"], "containerPath": ["abc3/bin/helics_plugin"] }, { "UUID": "abc5", "fileName": ["lib_plugin.so"], "installPath": ["/lib64/lib_plugin.so"], "containerPath": ["abc3/lib64/lib_plugin.so"] } ], "relationships": [ { "xUUID": "abc1", "yUUID": "abc2", "relationship": "Uses" }, { "xUUID": "abc4", "yUUID": "abc5", "relationship": "Uses" }, { "xUUID": "abc5", "yUUID": "abc2", "relationship": "Uses" }, { "xUUID": "abc0", "yUUID": "abc1", "relationship": "Contains" }, { "xUUID": "abc0", "yUUID": "abc2", "relationship": "Contains" }, { "xUUID": "abc3", "yUUID": "abc4", "relationship": "Contains" }, { "xUUID": "abc3", "yUUID": "abc5", "relationship": "Contains" } ] } ``` 注意:这些示例已简化,以展示根据提供的上下文文件产生的输出差异。 ## 运行 Surfactant 用于生成和合并 SBOM 以及处理样本上下文文件的 Surfactant TUI 可通过以下命令启动: ``` $ surfactant tui ``` 虽然 TUI 提供了生成 SBOM 的大多数选项,但在某些情况下可能需要直接运行 `generate` 命令以访问额外的命令行选项,或在无法使用 TUI 的环境中使用: ``` $ surfactant generate [OPTIONS] SPECIMEN_CONTEXT SBOM_OUTFILE [INPUT_SBOM] ``` **SPECIMEN_CONTEXT**:(必需)此前创建好的上下文文件,其中包含要包含在 SBOM 中的样本信息,或要为其生成 SBOM 的特定文件/目录路径(会使用一些隐含的默认上下文选项) **SBOM OUTPUT**:(必需)输出文件的期望名称 **INPUT_SBOM**:(可选)基础 SBOM,应谨慎使用,因为当文件在不同系统上安装时,关系可能会混乱 **--skip_gather**:(可选)跳过文件信息收集和软件条目添加 **--skip_relationships**:(可选)跳过基于元数据的关系添加 **--skip_install_path**:(可选)跳过为发现的文件包含安装路径,这可能导致“Uses”关系也不生成 **--recorded_institution**:(可选)收集 SBOM 数据的机构名称(默认:LLNL) **--output_format**:(可选)更改 SBOM 输出格式(给定实现 `write_sbom` 钩子的 Surfactant 插件完整模块名) **--input_format**:(可选)指定输入 SBOM 格式(给定实现 `read_sbom` 钩子的 Surfactant 插件完整模块名,默认为 cytrics) **--help**:(可选)显示帮助信息并退出 ## 理解 SBOM 输出 ### 软件 本节包含与样本中每个软件相关的条目列表。还包括文件大小、供应商、版本等元数据,以及用于唯一标识软件条目的 UUID。 ### 关系 本节包含每个软件条目之间的关联信息。 **Uses**:表示软件 x 使用软件 y,即 y 是 x 的辅助模块。 **Contains**:表示软件 x 包含软件 y(通常 x 是安装程序或 zip 等归档文件)。 ### 观察 本节包含有关各个软件组件的重要观察信息,例如漏洞、发现的特性等。 ## 合并 SBOM 包含多个独立 SBOM JSON 文件的文件夹可以使用 `merge_sbom.py` 合并,命令示例如下,该命令使用 `ls` 获取文件列表,然后使用 `xargs` 将结果文件列表传递给 `merge_sbom.py`: `ls -d ~/Folder_With_SBOMs/Surfactant-* | xargs -d '\n' surfactant merge --config_file=merge_config.json --sbom_outfile combined_sbom.json` 如果提供了合并配置文件选项,将创建一个顶层系统条目,所有其他软件条目都将与之关联(直接或间接基于其他关系)。指定空 UUID 将为新的系统条目生成随机 UUID,否则将使用提供的 UUID。 有关合并命令的详细信息可以在文档页面[此处](./docs/basic_usage.md#merging-sboms)找到。 ## 插件 Surfactant 支持使用插件来添加额外功能。用户可以使用 `surfactant plugin install` 安装插件,并使用 `surfactant plugin disable` 和 `surfactant plugin enable` 分别禁用或启用插件。`surfactant plugin install` 会检测活动的虚拟环境并运行相应的命令(即 `pipx` 或 `pip`)。或者,用户在使用 pipx 时可以使用 `pipx inject surfactant`,在使用 pip 时可以使用 `pip install` 来手动管理环境。 有关插件系统配置选项以及如何开发新插件的详细信息,请参考[此处](./docs/plugins.md)。 ## 支持 Surfactant 的完整用户指南可在[在线](https://surfactant.readthedocs.io)获取,也可在 [docs](./docs) 目录中找到。 如有疑问或支持,请在 [GitHub Discussions](https://github.com/LLNL/Surfactant/discussions/categories/q-a) 创建新讨论, 或[提交问题](https://github.com/LLNL/Surfactant/issues/new/choose)以报告错误和提出功能请求。 ## 贡献 欢迎贡献。修复错误或进行微小更改更推荐通过向 [Surfactant GitHub 仓库](https://github.com/LLNL/Surfactant) 提 pull request。 有关贡献的更多信息,请参考 [CONTRIBUTING](./CONTRIBUTING.md) 文件。 ## 许可证 Surfactant 在 MIT 许可证下发布。请参阅 [LICENSE](./LICENSE) 和 [NOTICE](./NOTICE) 文件以获取详细信息。所有新贡献必须在此许可证下进行。 SPDX-License-Identifier: MIT LLNL-CODE-850771
标签:CI测试, ELF分析, LLNL, MSI分析, PE分析, PyPI, Python框架, SBOM, WebSocket, 云安全监控, 依赖分析, 元数据提取, 开源成分分析, 文件信息提取, 文档生成, 模块化框架, 目录结构扫描, 硬件无关, 调试插件, 跌倒检测, 软件供应链安全, 软件物料清单, 进程保护, 远程方法调用, 逆向工具, 静态分析