17 KiB
English | 简体中文
安全
RustNet 处理不受信任的网络数据,因此纵深防御至关重要。本文档描述了已实现的安全措施。
目录
- Landlock 沙箱(Linux)
- Seatbelt 沙箱(macOS)
- FreeBSD 沙箱
- 权限剥离与 Job Object 沙箱(Windows)
- 权限需求
- 只读操作
- 不主动对外通信
- 日志文件隐私
- eBPF 安全
- 威胁模型
- 供应链安全
- 审计与合规
- 报告安全问题
Landlock 沙箱(Linux)
在 Linux 5.13+ 上,RustNet 使用 Landlock 在初始化后限制自身的 Linux capabilities。这样即使包解析存在漏洞被利用,也能限制损害范围。
受限制的内容
| 限制项 | 内核版本 | 描述 |
|---|---|---|
| 文件系统 | 5.13+ | 仅 /proc 可读(用于进程识别) |
| 网络 | 6.4+ | 禁止 TCP bind/connect(RustNet 为被动模式) |
| Linux capabilities | 任意 | pcap socket 打开后丢弃 CAP_NET_RAW |
| Linux capabilities | 任意 | eBPF 程序加载后丢弃 CAP_BPF、CAP_PERFMON、CAP_SYS_ADMIN |
| root uid | 任意 | 以 root 启动时(如 sudo rustnet),初始化完成后降权到调用用户(SUDO_UID/SUDO_GID)或 nobody |
| 特权 | 3.5+ | PR_SET_NO_NEW_PRIVS 由 RustNet 自身设置——始终生效,即使使用 --no-sandbox——防止通过 setuid 二进制文件提升特权 |
工作原理
- 初始化阶段:RustNet 加载 eBPF 程序、打开包捕获句柄、创建日志文件
- 特权锁定:设置
PR_SET_NO_NEW_PRIVS(即使禁用沙箱也会应用) - Linux capabilities 剥离:移除
CAP_NET_RAW、CAP_BPF、CAP_PERFMON和CAP_SYS_ADMIN - root uid 降权:以 root 运行时,通过
setresuid/setresgid切换到调用 sudo 的用户(或nobody)。已打开的捕获 socket、eBPF 程序和日志/导出文件继续有效。在没有 Landlock 的内核上,这是主要的隔离手段 - Landlock:限制文件系统和网络访问
安全收益
如果攻击者利用 DPI/包解析中的漏洞:
- 无法读取任意文件(凭据、配置等)
- 无法写入文件系统(除配置的日志路径外)
- 无法建立出站 TCP 连接(阻止数据外泄)
- 无法绑定 TCP 端口(阻止反向 shell)
- 无法创建新的 raw socket(Linux capabilities 已剥离)
- 无法通过 setuid 二进制文件提升特权(
PR_SET_NO_NEW_PRIVS,即使使用--no-sandbox也会设置) - 不以 root 运行:使用
sudo rustnet时进程会切换为调用用户,即使在没有 Landlock 的内核上,攻击者也无法获得 root
CLI 选项
--no-sandbox 禁用 Landlock 沙箱、Linux capabilities 剥离和 root uid 降权
(仍会设置 PR_SET_NO_NEW_PRIVS)
--sandbox-strict 要求完整沙箱强制生效,否则退出
--no-uid-drop 初始化后保持 root 运行,
不降权到 SUDO_UID/SUDO_GID(或 nobody)
root uid 降权的权衡:降权后,procfs 回退路径的进程归属只能检查目标用户拥有的进程,
/var/log/pods 下的 Kubernetes 日志目录也可能不可读。eBPF 快速路径(默认)不受影响。
如果依赖纯 procfs 归属(如未启用 eBPF 的构建)且需要归属其他用户的进程,请使用
--no-uid-drop。
优雅降级
- Kernel < 5.13:跳过沙箱,记录警告
- Kernel 5.13-6.3:仅文件系统限制
- Kernel 6.4+:完整的文件系统 + 网络限制
- Docker:Landlock 可能受限;应用正常运行
Seatbelt 沙箱(macOS)
在 macOS 10.5+ 上,RustNet 使用 Seatbelt(sandbox_init_with_parameters)在初始化后限制自身能力。这样即使包解析存在漏洞被利用,也能限制损害范围。
受限制的内容
| 限制项 | 描述 |
|---|---|
| 出站网络 | TCP/UDP 出站被阻止;Unix socket(Mach IPC)允许 |
| 文件系统读取 | 禁止读取用户主目录(/Users、/var/root);GeoIP 路径显式允许 |
| 文件系统写入 | 禁止写入所有用户主目录(/Users、/var/root) |
| 文件系统写入 | 仅配置的日志、JSON log、PCAP 和 PCAPNG 导出路径可写 |
| 进程执行 | 除 /usr/sbin/lsof 外,禁止执行所有二进制文件 |
| root uid | 以 root 启动时(如 sudo rustnet),初始化完成后降权到调用用户(SUDO_UID/SUDO_GID)或 nobody |
工作原理
- 初始化阶段:RustNet 打开包捕获句柄(BPF/PKTAP)并创建日志文件
- 预创建:PCAP sidecar 文件(
.connections.jsonl)和 PCAPNG 输出文件在沙箱应用前创建,因此其路径已经是有效的允许目标;同时移交给降权目标用户,确保降权后仍可写入 - root uid 降权:以 root 运行时,通过
setgid/setuid切换到调用 sudo 的用户(或nobody)。已打开的捕获和日志/导出文件描述符继续有效 - 沙箱应用:调用
sandbox_init_with_parameters;已打开的文件描述符保持不变,仅限制未来的操作
配置文件策略
RustNet 使用 默认允许 的 SBPL 配置文件配合针对性拒绝。拒绝默认的配置文件需要显式将所有系统库、Mach 端口、区域设置数据、字体和其他 OS 内部组件加入白名单——脆弱且容易出错。默认允许配合针对性拒绝覆盖了主要威胁(凭据窃取、数据外泄、shell 逃逸),同时避免操作风险。具体的拒绝规则阻止对用户主目录下的文件读/写、出站网络连接,以及除 /usr/sbin/lsof 外所有二进制文件的执行。
输出文件支持
--json-log、--pcap-export 和 --pcapng-export 路径通过运行时参数(JSON_LOG_PATH、PCAP_PATH、PCAP_JSONL_PATH、PCAPNG_PATH)传递给 SBPL 配置文件。配置文件为每个路径授予显式的 allow file-write* 规则,该规则通过 SBPL 的特异性优先于更宽泛的 /Users 拒绝规则。未使用的参数默认为 /dev/null。
三个标志在沙箱内均可正常工作。
安全收益
如果攻击者利用 DPI/包解析中的漏洞:
- 无法读取
/Users下的 SSH 密钥、AWS 凭据、浏览器配置文件或其他凭据文件 - 无法写入
/Users下的 SSH 密钥、AWS 凭据、浏览器配置文件或其他凭据文件 - 无法建立出站 TCP/UDP 连接(阻止数据外泄)
- 无法打开新的 raw network socket
- 无法执行二进制文件(不能通过
/bin/sh、/usr/bin/curl等逃逸 shell) - 不以 root 运行:使用
sudo rustnet时进程会切换为调用用户
CLI 选项
--no-sandbox 禁用 Seatbelt 沙箱和 root uid 降权
--sandbox-strict 要求完整沙箱强制生效,否则退出
--no-uid-drop 初始化后保持 root 运行,
不降权到 SUDO_UID/SUDO_GID(或 nobody)
root uid 降权的权衡:默认的 PKTAP 归属路径不受影响(进程元数据随已打开的捕获
fd 带内到达),但 lsof 回退路径(PKTAP 不可用时启用,例如显式指定 --interface)
降权后只能看到目标用户的进程。如果依赖 lsof 归属其他用户的进程,请使用
--no-uid-drop。
为什么默认使用 BestEffort
sandbox_init_with_parameters 是 macOS 的私有(未公开)API。自 macOS 10.5 以来一直保持稳定,Chromium、Firefox 和 Safari 都使用它进行进程沙箱,但理论上可能在没有通知的情况下发生变化。BestEffort 在 API 行为异常时优雅降级,而不是阻止应用运行。使用 --sandbox-strict 可要求沙箱生效,否则中止。
剪贴板行为
与 Linux Landlock 不同,在 Seatbelt 下剪贴板复制(c 键)正常工作。macOS 剪贴板使用 NSPasteboard,通过 Mach IPC 在 Unix domain socket 上通信——SBPL 配置文件显式允许 (network-outbound (remote unix-socket))。
在 Linux 上,剪贴板需要访问 Wayland socket(/run/user/UID/wayland-0)或 X11 socket(/tmp/.X11-unix/)。Landlock 的拒绝默认模型会阻止这些,因为它们不在写路径的允许列表中,因此当 Landlock 激活时剪贴板不可用。
FreeBSD 沙箱
FreeBSD 当前未启用沙箱。计划使用 cap_enter() 配合 libcasper 实现完整的 Capsicum 沙箱,用于特权进程查找——详见 ROADMAP.md。
root uid 降权
在 Capsicum 落地之前,FreeBSD 上的主要隔离手段是 root 降权:以 root 启动时(如 sudo rustnet),BPF 捕获设备打开后,进程通过 setresuid/setresgid 降权到调用用户(SUDO_UID/SUDO_GID)或 nobody。已打开的捕获和日志/导出文件描述符继续有效,预创建的导出文件会移交给目标用户。注意 doas 不设置 SUDO_UID,因此 doas 用户会回退到 nobody。
权衡:进程归属使用 sockstat,非 root 用户只能看到目标用户的 socket。如需归属其他用户的进程,请使用 --no-uid-drop。
--no-uid-drop 初始化后保持 root 运行,
不降权到 SUDO_UID/SUDO_GID(或 nobody)
权限剥离与 Job Object 沙箱(Windows)
在 Windows 上,RustNet 在初始化后从进程令牌中移除危险特权,并应用 Job Object 阻止子进程创建。
受限制的内容
| 限制项 | 描述 |
|---|---|
| 特权移除 | 永久移除 SeDebugPrivilege、SeTakeOwnershipPrivilege、SeBackupPrivilege、SeRestorePrivilege 等危险特权 |
| 子进程 | Job Object 阻止创建子进程(反向 shell、基于 exec 的数据外泄) |
工作原理
- 初始化阶段:RustNet 打开 Npcap 句柄并创建日志文件
- 特权移除:
AdjustTokenPrivileges配合SE_PRIVILEGE_REMOVED永久从进程令牌中剥离危险特权 - Job Object:应用
JOB_OBJECT_LIMIT_ACTIVE_PROCESS = 1的 Job Object,阻止任何子进程创建
安全收益
如果攻击者利用 DPI/包解析中的漏洞:
- 无法调试其他进程(SeDebugPrivilege 已移除)
- 无法取得任意文件的所有权(SeTakeOwnershipPrivilege 已移除)
- 无法通过 ACL 绕过读取文件(SeBackupPrivilege 已移除)
- 无法生成子进程(cmd.exe、powershell.exe、curl.exe —— 被 Job Object 阻止)
- 无法加载内核驱动(SeLoadDriverPrivilege 已移除)
局限性
Windows 沙箱弱于 Linux/macOS/FreeBSD:
- 无文件系统限制 —— Windows 缺少与 Landlock 或 Seatbelt 等效的进程级文件系统沙箱
- 无网络限制 —— 阻止出站会中断 Npcap 包捕获
- 特权移除仅影响提升进程已拥有的特权
CLI 选项
--no-sandbox 禁用特权移除和 Job Object
--sandbox-strict 要求完整沙箱强制生效,否则退出
权限需求
RustNet 需要特权访问来捕获网络数据包:
| 平台 | 需求 |
|---|---|
| Linux | CAP_NET_RAW 这项 Linux capability 或 root |
| macOS | Root 或 BPF 组成员(access_bpf 组) |
| Windows | Administrator(用于 Npcap) |
| FreeBSD | Root 或 BPF 设备访问 |
为什么需要特权
- Raw socket 访问 —— 在低层拦截网络流量(只读、非混杂模式)
- BPF 设备访问 —— 将包过滤器加载到内核
- eBPF 程序 —— 可选的内核探针,用于增强进程追踪(仅限 Linux)
推荐:基于 Linux capabilities 的执行(Linux)
与其以 root 运行,不如仅授予所需的 Linux capabilities:
# 现代 Linux(5.8+):包捕获 + eBPF
sudo setcap 'cap_net_raw,cap_bpf,cap_perfmon+eip' $(which rustnet)
# 仅包捕获(eBPF 会回退到 procfs)
sudo setcap cap_net_raw+eip $(which rustnet)
旧版 pre-5.8 内核需要宽泛的 CAP_SYS_ADMIN 才能执行 eBPF 操作。RustNet
的安装包不会自动授予该 capability;除非你明确接受该风险,否则请只授予
CAP_NET_RAW 并使用 procfs 回退。沙箱应用后,CAP_NET_RAW 和 eBPF
加载相关 capabilities 会被丢弃——进程仅保留所需的最小特权。
只读操作
RustNet 仅监控流量,不会:
- 修改数据包
- 阻断连接
- 注入流量
- 更改路由表
- 更改防火墙规则
包捕获以非混杂、只读模式打开。
不主动对外通信
RustNet 完全在本地运行:
- 无遥测或分析
- 无网络请求(除监控的流量外)
- 无云服务或远程 API
- 所有数据保留在你的系统上
日志文件隐私
日志文件可能包含敏感信息:
- IP 地址和端口
- 主机名和 SNI 数据
- 进程名和 PID
- DNS 查询和响应
最佳实践:
- 默认禁用日志记录(不使用
--log-level标志) - 保护日志目录权限
- 实施日志轮转和保留策略
- 分享前检查日志中的敏感数据
eBPF 安全
使用 eBPF 进行增强型进程检测时(Linux 默认):
- 现代内核需要额外的 Linux capabilities(
CAP_BPF、CAP_PERFMON) - eBPF 程序在加载前由内核验证
- 仅限只读操作(不修改数据包)
- 如果 eBPF 失败,自动回退到 procfs
威胁模型
RustNet 防护的内容:
- 未经授权的用户无法在没有适当权限的情况下捕获数据包
- 基于 Linux capabilities 的权限限制了被入侵后的影响范围
- Landlock(Linux)和 Seatbelt(macOS)沙箱限制潜在的漏洞利用
RustNet 不防护的内容:
- 拥有包捕获权限的用户可以看到所有未加密的流量
- Root/Administrator 用户可以直接修改 RustNet 或捕获数据包
- 对机器的物理访问可以捕获数据包
- 网络级攻击(RustNet 是监控工具,不是安全设备)
以 Root 身份运行时的沙箱
Landlock(Linux)和 Seatbelt(macOS)即使在 RustNet 以 root(UID 0)运行时也会强制执行限制。沙箱一旦应用就无法从进程内部撤销——在 Linux 上,RustNet 会在应用任何限制之前直接设置 PR_SET_NO_NEW_PRIVS(Landlock 也需要并会同样设置它),该设置对每个进程不可逆,并且即使使用 --no-sandbox 也会应用。
然而,沙箱不能防护供应链攻击。被入侵的二进制文件可以直接不应用沙箱。Root 也可以:
- 传递
--no-sandbox完全跳过沙箱(PR_SET_NO_NEW_PRIVS除外) - 卸载 Landlock LSM 内核模块
- 在 macOS 上禁用 SIP(控制沙箱强制执行)
- 使用
ptrace修改运行中的进程
因此,强烈建议使用细粒度 Linux capabilities(setcap cap_net_raw=eip)运行,而不是以 root 运行。
供应链安全
RustNet 采取以下措施防护供应链攻击:
- 依赖锁文件:
Cargo.lock已提交到仓库,固定所有传递依赖版本并记录源校验和。这防止静默版本升级。 - 安全审计:
cargo deny check在每次 push 和 pull request 时于 CI 中运行,对照 RustSec Advisory Database 检查依赖,并强制执行许可证、来源和通配符版本策略(deny.toml)。一个每日定时工作流会针对已提交的Cargo.lock重新检查安全公告,因此新发布的公告无需 push 即可被发现。 - CI action 固定:所有 GitHub Actions 均通过 commit SHA(而非标签)固定,防止对上游 action 的标签重写攻击。
- 保守的依赖策略:新依赖需要说明理由,并审查其维护状态和安全记录(参见 CONTRIBUTING.zh-CN.md)。
- 构建时完整性:Windows Npcap SDK 下载在
build.rs中对照硬编码的 SHA256 校验和进行验证。 - 代码签名:macOS 发布版本使用 Apple Developer 证书签名并进行公证。
- 校验和验证:所有打包工作流(Homebrew、Chocolatey、AUR)在发布前计算并双重验证 SHA256 校验和。
局限性
cargo install rustnet从 crates.io 获取最新兼容版本,并不使用Cargo.lock。从源码构建的用户应验证源 tarball 校验和。- 构建脚本(
build.rs)和 proc-macros 在编译时执行任意代码。虽然所有当前依赖都是久经考验的 crate,但这是 Rust 构建模型的固有风险。
审计与合规
对于生产环境:
- 审计记录谁以包捕获权限运行 RustNet
- 网络监控策略和数据保护法规合规
- 对特权网络访问进行用户访问审查
- 通过配置管理系统实现自动化 Linux capabilities 管理
报告安全问题
请通过 GitHub Issues 报告安全漏洞,或直接与维护者联系。