[](https://github.com/timescale/ressrf/actions/workflows/ci.yml)
[](https://opensource.org/licenses/MIT)
一个多平台 SSRF 防御库,具有经过模糊测试的 Rust 核心、可插拔的协议传输、可插拔的审计日志,并提供 Go、Python 和 Node.js 的绑定。
ressrf(发音同 "resurf")会在发起任何连接之前,根据可配置的拒绝/允许策略验证网络目标。默认情况下,它会阻止对私有网络、云元数据端点(AWS IMDS、Azure Wireserver、GCP metadata)、链路本地地址和其他内部网段的访问。协议适配器在 DNS 解析和建立连接阶段介入,为 HTTP 客户端、TCP 连接和 SSH 会话提供透明的保护。
## 主要特性
- **拒绝优先的策略引擎**,内置预设、自定义允许/拒绝 CIDR 列表、URL 规则以及云服务提供商模块
- **默认拒绝列表**源自 IANA 特殊用途注册表,并通过每月自动更新保持最新
- 支持所有语言的**协议适配器**:HTTP(重定向重验证)、TCP(DNS 固定拨号)和 SSH
- 通过简单的回调接口实现**可插拔的审计日志**,在所有绑定中保持一致
- 通过共享的 JSON 测试向量保证**跨语言一致性**
- 使用 cargo-fuzz 进行**模糊测试**(每周由 CI 执行)
## 包
| Package | 语言 | 集成方式 | 文档 |
|---------|----------|-------------|------|
| [`ressrf-core`](crates/ressrf-core/) | Rust | 直接依赖 | [README](crates/ressrf-core/README.md) |
| [`ressrf-tcp`](crates/ressrf-tcp/) | Rust | DNS 固定的 TCP 拨号 | [README](crates/ressrf-tcp/README.md) |
| [`ressrf-http`](crates/ressrf-http/) | Rust | Tower Layer/Service | [README](crates/ressrf-http/README.md) |
| [`ressrf-ssh`](crates/ressrf-ssh/) | Rust | russh/async-ssh2 的 Guard | [README](crates/ressrf-ssh/README.md) |
| [`ressrf-tracing`](crates/ressrf-tracing/) | Rust | TracingSink 审计适配器 | [README](crates/ressrf-tracing/README.md) |
| [`ressrf-wasm`](crates/ressrf-wasm/) | Rust | 用于 Go/Node.js 的 WASM ABI | [README](crates/ressrf-wasm/README.md) |
| [`go/ressrf`](go/ressrf/) | Go | wazero WASM runtime | [README](go/ressrf/README.md) |
| [`go-native/ressrf`](go-native/ressrf/) | Go | 原生移植(无 WASM,无 CGO) | [README](go-native/ressrf/README.md) |
| [`python/`](python/) | Python | PyO3 原生扩展 | [README](python/README.md) |
| [`node/`](node/) | TypeScript | WebAssembly API | [README](node/README.md) |
```
┌─────────────────────────┐
│ ressrf-core │
│ (policy, CIDR, URI, │
│ audit, cloud, trie) │ ┌──────────────────────┐
└───────┬─────────────────┘ │ Go (native) │
│ │ pure-Go port │
┌─────────────────┼─────────────────┐ │ │
│ │ │ │ Consumes only the │
▼ ▼ ▼ │ shared JSON: │
┌────────────────┐ ┌─────────────┐ ┌────────────────┐ │ • config/*.json │
│ ressrf-wasm │ │ ressrf-http │ │ ressrf-ssh │ │ • tests/vectors │
│ (WASM ABI) │ │ (Tower) │ │ (russh) │ │ │
└───────┬────────┘ └──────┬──────┘ └───────┬────────┘ │ No Rust dependency; │
│ │ │ │ pinned to ressrf- │
┌─────┴─────┐ └───────┬─────────┘ │ core via differen- │
│ │ │ │ tial fuzz against │
▼ ▼ ▼ │ ressrf-wasm. │
┌──────────┐ ┌──────────┐ ┌──────────────┐ └──────────────────────┘
│Go(wazero)│ │ Node.js │ │ Python │
│ binding │ │ (WASM) │ │ (PyO3) │
└──────────┘ └──────────┘ └──────────────┘
```
原生 Go 移植版位于 [`go-native/ressrf/`](go-native/ressrf/)。它非常适合那些倾向于使用原生调试能力(`pprof`、`delve`)以及不希望将 Rust 工具链引入 PR 贡献流程的 Go 团队。
## 快速开始
### Rust
```
use ressrf_core::{PolicyBuilder, UriValidator};
let policy = PolicyBuilder::external_only().build();
assert!(policy.is_network_allowed(&["10.0.0.1".parse().unwrap()]).is_err());
assert!(policy.is_network_allowed(&["93.184.216.34".parse().unwrap()]).is_ok());
```
### Go(wazero,共享 Rust 引擎)
```
policy, _ := ressrf.NewPolicyBuilder(ressrf.PresetExternalOnly).
WithCloudProviders("aws", "azure", "gcp").
Build(ctx)
defer policy.Close(ctx)
err := policy.IsAllowed(ctx, "http://169.254.169.254/latest/meta-data/")
// err: blocked
```
### Go(原生)
```
policy, _ := ressrf.NewPolicy(ressrf.PresetExternalOnly,
ressrf.WithCloudProviderDenies(ressrf.CloudAWS, ressrf.CloudAzure, ressrf.CloudGCP),
)
err := policy.IsAllowed(ctx, "http://169.254.169.254/latest/meta-data/")
// err: blocked
```
### Python
```
from ressrf import Policy, RessrfBlockedError
policy = Policy.external_only(cloud=["aws"])
try:
policy.validate_url("http://169.254.169.254/latest/meta-data/")
except RessrfBlockedError as e:
print(f"Blocked: {e.reason}")
```
### Node.js
```
import { Policy, isBlocked } from "ressrf";
const policy = await Policy.externalOnly({ cloud: ["aws"] });
try {
policy.isAllowed("http://169.254.169.254/latest/meta-data/");
} catch (err) {
if (isBlocked(err)) console.log("Blocked:", err.reason);
}
```
## 安装
| 语言 | 命令 | 要求 |
|----------|---------|--------------|
| Rust | `cargo add ressrf-core` | Rust 1.75+ |
| Go (wazero) | `go get github.com/timescale/ressrf/go/ressrf` | Go 1.26+ |
| Go (原生) | `go get github.com/timescale/ressrf/go-native/ressrf` | Go 1.25+ |
| Python | `pip install ressrf` | Python 3.10+ |
| Node.js | `npm install ressrf` | Node.js 20+ |
请参阅各个包的 README 了解可选的附加功能(协议适配器、功能标志)。
## 允许列表
允许规则会覆盖拒绝规则。您可以为特定的 CIDR 打通孔洞,同时保持对其余私有地址空间的拦截:
```
// Rust
PolicyBuilder::external_only().add_allowed(&["10.42.0.0/16"]).build();
```
```
// Go (wazero)
NewPolicyBuilder(PresetExternalOnly).WithAllowedCIDRs("10.42.0.0/16").Build(ctx)
```
```
// Go (native)
ressrf.NewPolicy(ressrf.PresetExternalOnly, ressrf.WithAllowedCIDRs("10.42.0.0/16"))
```
```
# Python
Policy.external_only(allowed=["10.42.0.0/16"])
```
```
// Node.js
await Policy.externalOnly({ allowCidrs: ["10.42.0.0/16"] });
```
## URL 规则
用于在基于 CIDR 的过滤之外,实现 URL 级别的允许/拒绝。规则对主机使用 glob 模式(`*` = 单个 DNS 标签),对路径也使用 glob 模式(`*` = 单个分段,`**` = 任意深度),并可选择使用 regex 处理复杂模式:
```
// Rust
PolicyBuilder::external_only()
.url_allow(UrlRule::glob("https", "*.stripe.com", "/v1/**"))
.url_deny(UrlRule::host("*.internal"))
.build();
```
```
// Go (wazero)
NewPolicyBuilder(PresetExternalOnly).
WithURLAllow(URLRule{Scheme: "https", Host: "*.stripe.com", Path: "/v1/**"}).
WithURLDeny(URLRule{Host: "*.internal"}).
Build(ctx)
```
```
// Go (native)
ressrf.NewPolicy(ressrf.PresetExternalOnly,
ressrf.WithURLAllow(ressrf.URLRuleGlob("https", "*.stripe.com", "/v1/**")),
ressrf.WithURLDeny(ressrf.URLRuleGlob("", "*.internal", "")),
)
```
```
# Python
PolicyBuilder("external_only") \
.url_allow(scheme="https", host="*.stripe.com", path="/v1/**") \
.url_deny(host="*.internal") \
.build()
```
```
// Node.js
new PolicyBuilder("external_only")
.urlAllow({ scheme: "https", host: "*.stripe.com", path: "/v1/**" })
.urlDeny({ host: "*.internal" })
.build();
```
系统会首先检查拒绝规则。当配置了允许规则时,任何不匹配允许规则的 URL 都将被拦截。在允许规则上设置 `bypass_ip_check: true` 可以跳过对受信任端点的 IP 级别检查。
## 审计日志
所有绑定都暴露了相同的可插拔接口。该库会输出结构化事件,但绝不指定必须使用哪种日志框架:
```
// Rust: implement the AuditSink trait
let policy = PolicyBuilder::external_only()
.audit_sink(Box::new(my_sink))
.build();
```
```
// Go: any function works
sink := ressrf.AuditFunc(func(ctx context.Context, e *ressrf.AuditEvent) {
slog.InfoContext(ctx, "ressrf", "kind", e.Kind)
})
```
```
# Python: 任何 callable 均可
sink = AuditFunc(lambda event: print(f"[{event.event_type}] {event.fields}"))
```
```
// Node.js: any object with emit() works
const sink = new AuditFunc((event) => console.log(event.kind, event.fields));
```
## IP 范围代码生成
`scripts/generate_ip_ranges.py` 会从 IANA、AWS、Azure 和 GCP 获取上游 IP 范围数据。每月一次的 CI 工作流会验证更改并自动发起 PR。服务范围可在运行时通过 `ServiceRangeTable` 进行查询(基于字典树,O(log n) 查询复杂度)。
```
python scripts/generate_ip_ranges.py # full update
python scripts/generate_ip_ranges.py --iana-only # skip cloud service ranges
python scripts/generate_ip_ranges.py --validate-only
```
## 测试
`tests/vectors/` 中的共享测试向量确保了所有语言下的行为完全一致,其中包括一个包含 92 个测试用例的 `ssrf_techniques.json`,涵盖了完整的 SSRF 绕过技术分类(IP 表示技巧、IPv6 变体、解析器混淆、协议走私、云元数据、Unicode/IDN 等):
```
cargo test --workspace --all-features # Rust
cd go/ressrf && go test -race ./... # Go (wazero)
cd go-native/ressrf && go test -race ./... # Go (native)
cd python && uv run pytest tests/ -v # Python
cd node && npx tsx --test tests/*.test.ts # Node.js
```
位于 `crates/ressrf-tcp/tests/ssrf_e2e.rs` 的 Tier 2 端到端测试套件,利用 CoreDNS 和 WireMock 容器(`tests/containers/`),在整个网络协议栈中测试了 DNS 重绑定固定和重定向链。该测试受 `e2e` Cargo feature 限制且需要 Docker;当 Docker 不可用时,测试将附带提示并自动跳过:
```
cargo test --features e2e -p ressrf-tcp --test ssrf_e2e
```
## CI/CD
- **Rust:** check、fmt、clippy、test (Linux/macOS/Windows)、WASM 构建
- **Go (wazero + 原生):** test (多操作系统、竞态检测器)、vet、golangci-lint;原生移植版还会额外运行针对 wazero 绑定的 WASM 预言机的差分模糊测试任务
- **Python:** pytest (多操作系统)、ruff、ty
- **Node.js:** node:test (多操作系统)、tsc
- **SSRF e2e:** 仅限 Linux 的 Tier 2 任务会启动 CoreDNS + WireMock,以端到端验证基于 DNS 和重定向的绕过行为
- **安全:** cargo audit、govulncheck、cargo-fuzz (每周)、zizmor
- **IP 范围:** 每月一次的上游数据获取、验证、测试以及自动发起 PR
## 贡献
如果您希望看到与我们集成了您最喜欢的编程语言、云服务提供商、协议或库,欢迎发起 issue 或提交 pull request。我们欢迎各种形式的贡献。
请参阅 [HACKING.md](HACKING.md) 了解开发环境设置、测试,以及添加新云服务提供商、语言绑定、协议适配器和客户端库集成的分步指南。
## 许可证
MIT