SecurityRonin/git-forensic

GitHub: SecurityRonin/git-forensic

纯 Rust 实现的 Git 取证审计库,直接读取 `.git` 对象存储以检测日期倒填、历史重写、未签名提交和不可达对象等仓库异常。

Stars: 0 | Forks: 0

# git-forensic [![git-core](https://img.shields.io/crates/v/git-core.svg?label=git-core)](https://crates.io/crates/git-core) [![git-forensic](https://img.shields.io/crates/v/git-forensic.svg?label=git-forensic)](https://crates.io/crates/git-forensic) [![Docs.rs](https://img.shields.io/docsrs/git-forensic)](https://docs.rs/git-forensic) [![License: Apache-2.0](https://img.shields.io/badge/License-Apache--2.0-blue.svg)](LICENSE) [![CI](https://static.pigsec.cn/wp-content/uploads/repos/2026/06/f0e38df722032016.svg)](https://github.com/SecurityRonin/git-forensic/actions) [![Sponsor](https://img.shields.io/badge/sponsor-h4x0r-ea4aaa?logo=github-sponsors)](https://github.com/sponsors/h4x0r) **一个从零开始构建的 Git 对象存储读取器和分级异常审计器 —— 直接从磁盘读取松散对象和打包对象,并揭示出被干净的 `git log` 设计为隐藏的日期倒填的提交、被重写的历史、未签名的提交以及可恢复的已丢弃对象。** 两个 crate,同一个 workspace: - **[`git-core`](https://crates.io/crates/git-core)** — 读取器:支持读取松散对象 + packfile(v2, OFS/REF delta)对象、refs、提交、树和 reflog,构建于内容寻址的 Merkle DAG 之上。纯 Rust 实现,无 `unsafe`,无 `libgit2`/C 绑定 —— 可读取任何操作系统的 `.git`。 - **[`git-forensic`](https://crates.io/crates/git-forensic)** — 审计器:将解析出的提交、reflog、签名和可达性转化为严重程度分级的 [`forensicnomicon::report::Finding`](https://crates.io/crates/forensicnomicon),使得代码仓库的异常能够与取证工具体系中的其他部分统一聚合。 ## 在 30 秒内审计一个代码仓库 ``` [dependencies] git-forensic = "0.1" # pulls in git-core ``` ``` use git_forensic::{audit_repo, source}; use git_core::GitRepo; use std::path::Path; let repo = GitRepo::open(Path::new("/path/to/.git"))?; let head = repo.head()?; // Walk every commit reachable from HEAD; get back graded anomalies. for anomaly in audit_repo(&repo, head)? { let finding = anomaly.to_finding(source("repo")); println!("[{:?}] {} — {}", finding.severity, finding.code, finding.note); // e.g. [Some(Medium)] GIT-COMMIT-TIME-INVERSION — committer timestamp … precedes author … } # Ok::<(), git_core::GitError>(()) ``` `audit_repo` 从起始哈希值开始遍历提交,并对其发现的内容进行分级。损坏或无法读取的对象会作为类型化的错误呈现,绝不会引发 panic。 ## 异常代码 每种异常都是一个**观察结果**(“与……相符”);由审查人员得出结论。这些代码是稳定且公开的契约。 | 代码 | 严重程度 | 观察结果 | |---|---|---| | `GIT-COMMIT-TIME-INVERSION` | 中 | 某个提交的提交者时间戳早于其作者时间戳 —— 与时间戳倒填相符(良性原因:跨机器时钟偏差) | | `GIT-HISTORY-REWRITE` | 中 | 某个 reflog 条目的操作重写了历史(`reset` / `rebase` / `amend` / `filter-branch` / 强制更新) —— 先前的 tip 仍然可恢复 | | `GIT-UNSIGNED-IN-SIGNED-HISTORY` | 中 | 在一个以签名为主的历史中存在未签名的提交 —— 与在现行签名策略之外注入的提交相符(良性原因:遗忘的签名) | | `GIT-UNREACHABLE-OBJECT` | 中 / 低 | 无法从任何 ref 到达的对象 —— 是删除或重写历史的残留物,在执行 `gc` 之前仍可恢复(丢弃的**提交**定为中级;松散的 blob/树定为低级) | 检查结果来自于分析器的入口点:`audit_repo` / `audit_commit` (`GIT-COMMIT-TIME-INVERSION`),`audit_reflog` / `audit_reflog_entries` (`GIT-HISTORY-REWRITE`),`audit_signatures` / `audit_signatures_repo` (`GIT-UNSIGNED-IN-SIGNED-HISTORY`),以及 `audit_unreachable` (`GIT-UNREACHABLE-OBJECT`)。`attribution` 模块构建了审查人员用于叙述的“谁在何时做了什么”的时间线。 ## 读取器:导航对象存储 `GitRepo`(位于 `git-core` 中)直接从 `.git` 目录读取对象、refs、提交和树 —— 包括松散对象和 v2 packfile: ``` use git_core::GitRepo; use std::path::Path; let repo = GitRepo::open(Path::new("/path/to/.git"))?; // Resolve HEAD and read the commit it points at… let head = repo.head()?; let commit = repo.read_commit(&head)?; println!("{} by {}", commit.hash.to_hex(), commit.author.name); // …walk first-parent history, or enumerate every object in the store. for commit in repo.walk_commits(head) { let _ = commit?; } for hash in repo.all_objects()? { println!("{}", hash.to_hex()); } # Ok::<(), git_core::GitError>(()) ``` 由于 crates.io 上基础的 crate 名称 `git` 已被占用,因此该 crate 以 `git-core` 的名称发布,并在代码中作为 `git_core` 导入。 ## 与通用 Git 库的区别 大多数 Git 库只回答一个问题:“这个代码仓库包含什么?”而这个 workspace 回答的是数字取证审查人员真正需要的问题: | 功能 | 通用 Git 库 | 本 workspace | |---|---|---| | 松散对象读取 + 解压 | ✅ | ✅ | | Packfile v2 读取 (OFS / REF delta 解析) | ✅ | ✅ | | 提交 / 树 / ref / reflog 解析 | ✅ | ✅ | | First-parent 提交遍历 | ✅ | ✅ | | 提交时间倒转(日期倒填)检测 | — | ✅ | | Reflog 历史重写残留(`reset` / `rebase` / `amend` / 强制推送) | — | ✅ | | 签名历史中的未签名检测 | — | ✅ | | 不可达对象(被丢弃的历史)枚举 | — | ✅ | | 归属时间线(作者/提交者,时区) | — | ✅ | | 严重程度分级的 `report::Finding` 输出 | — | ✅ | | 纯 Rust 实现,无 `libgit2` / C 绑定 | 部分 | ✅ | | `#![forbid(unsafe_code)]` | — | ✅ | ## 信任,但要核实 `git-forensic` 是专为处理来自潜在受损系统的不可信对象存储而构建的: - **`#![forbid(unsafe_code)]`** 覆盖了两个 crate —— 没有 C 绑定,没有 `libgit2`,没有 FFI。它可以读取任何操作系统的 `.git`。 - **面对恶意输入不会 Panic** —— 每个长度、偏移量和 delta 指令都根据声明的大小和实际缓冲区进行了验证;该 workspace 在生产代码中禁用了 `clippy::unwrap_used` 和 `clippy::expect_used`。 - **经过模糊测试** —— 四个 `cargo-fuzz` 目标(`loose`、`commit`、`tree`、`delta`);`fuzz.yml` CI 工作流会构建并对每个目标进行冒烟测试。 - **在真实工件上得到验证** —— 读取器在真实的 `.git` 目录上进行了测试,对象解压和 packfile delta 解析均与 `git` 本身进行了交叉校验。 ``` cargo test cargo +nightly fuzz run delta # requires nightly + cargo-fuzz ``` ## 适用场景 `git-core` 是 SecurityRonin 取证系列工具的 Git 内容寻址存储基础。它位于 GRAPH NAVIGATION 层 —— 通过哈希值导航 Merkle DAG —— 并将分级检查结果提供给 [`issen`](https://github.com/SecurityRonin/issen) 以进行跨工件关联。内容寻址和软件供应链领域的相关生态 crate: | Crate | 角色 | |---|---| | [`forensicnomicon`](https://crates.io/crates/forensicnomicon) | **KNOWLEDGE** — 每个分析器都会发出的共享 `report::Finding` 模型 | | [`issen`](https://github.com/SecurityRonin/issen) | **Orchestrator** — 连接每一个取证路径并关联检查结果 | | [`ntfs-forensic`](https://github.com/SecurityRonin/ntfs-forensic) | NTFS 文件系统读取器 + 异常审计器 | [隐私政策](https://securityronin.github.io/git-forensic/privacy/) · [服务条款](https://securityronin.github.io/git-forensic/terms/) · © 2026 Security Ronin Ltd
标签:Git, Rust, 可视化界面, 域渗透, 安全可观测性, 版本控制, 电子数据取证, 网络流量审计