ayuhito/safehttp
GitHub: ayuhito/safehttp
safehttp 是一个基于 Go net/http 的防 SSRF HTTP 客户端包装器,在出站请求中拦截内部和特殊用途地址。
Stars: 4 | Forks: 0
# safehttp
[](https://pkg.go.dev/github.com/ayuhito/safehttp)
`safehttp` 是一个针对 Go 的 `net/http` 的防 SSRF 包装器,适用于 URL 由不受信任的
来源提供的出站请求。
当你的服务从用户、webhook、OAuth metadata、
导入的文档、第三方 API payload 或任何其他你无法完全控制的来源获取 URL 时,请使用它。
它将这些请求限制在允许的公共目标内,并阻止
loopback、RFC1918 网络、Kubernetes、cloud metadata
以及其他内部或特殊用途的地址。
## 默认配置
`NewClient()` 默认采用仅允许公共 HTTPS 的配置。
请求必须使用 HTTPS,针对公共目标,并使用端口 `443`。URL
凭证、自定义 `Request.Host`、proxy、其他 scheme 或端口,以及
内部或特殊用途的 IP 范围都会被阻止。
默认会跟随重定向,但每个重定向目标都会被重新验证。
## 安装
```
go get github.com/ayuhito/safehttp
```
## 用法
创建一个 client 并重复使用它。
```
client, err := safehttp.NewClient(
safehttp.ClientTimeout(5*time.Second),
safehttp.MaxResponseBytes(10<<20),
safehttp.NoRedirects(),
)
if err != nil {
return err
}
resp, err := client.Get(rawURL)
if err != nil {
return err
}
defer resp.Body.Close()
```
如果受信任的目标是已知的 base URL,请允许其确切的 origin。
path、query string 和 fragment 会被忽略。策略匹配的是规范化的
scheme、host 和有效端口。
```
client, err := safehttp.NewClient(
safehttp.AllowOrigins("https://api.example.com"),
safehttp.AllowMethods(http.MethodGet),
safehttp.MaxRedirects(3),
safehttp.ClientTimeout(5*time.Second),
safehttp.MaxResponseBytes(8<<20),
)
```
`AllowOrigins` 是一个精确的元组策略。多个 origin 不会在
scheme、host 和 port 之间产生交叉乘积的允许范围。地址检查仍然
适用,因此 loopback 或私有测试服务器需要显式的 `AllowCIDRs`
授权。
当策略确实基于 host 模式时(例如多个精确的 host 或通配符域族),请使用 `AllowHosts`。请将其与显式的 scheme
和 port 搭配使用。
```
client, err := safehttp.NewClient(
safehttp.AllowHosts(
"api.github.com",
"uploads.github.com",
"*.githubusercontent.com",
),
safehttp.AllowSchemes("https"),
safehttp.AllowPorts(443),
safehttp.AllowMethods(http.MethodGet, http.MethodHead),
safehttp.MaxRedirects(3),
safehttp.ClientTimeout(5*time.Second),
safehttp.MaxResponseBytes(8<<20),
)
```
## 现有 Transport
使用 `NewTransport` 可以复用现有的 transport 配置。
```
base := http.DefaultTransport.(*http.Transport).Clone()
base.MaxIdleConnsPerHost = 32
rt, err := safehttp.NewTransport(base, safehttp.AllowOrigins("https://api.github.com"))
if err != nil {
return err
}
client := &http.Client{Transport: rt}
```
`safehttp` 在应用其设置之前会克隆 transport,因此原始的
transport 不会被修改。请使用 `safehttp.Dialer` 进行自定义 dialer 设置。
那些绕过 safehttp 连接检查或禁用 TLS
证书验证的 transport 设置将被拒绝。
## 仅 Guard 检查
`NewGuard` 暴露了验证功能,而无需构造 `http.Client`。
```
guard, err := safehttp.NewGuard(safehttp.AllowOrigins("https://api.github.com"))
if err != nil {
return err
}
if err := guard.CheckRequest(req); err != nil {
return err
}
```
使用仅 guard 检查进行预检验证。它们不会发送请求;
对于出站 HTTP 路径,请使用 `NewClient` 或 `NewTransport`。
## API 参考
构造函数:
```
func NewClient(opts ...Option) (*http.Client, error)
func NewTransport(base *http.Transport, opts ...Option) (http.RoundTripper, error)
func NewGuard(opts ...Option) (*Guard, error)
```
选项:
- 精确目标策略:`AllowOrigins`
- 组件目标策略:`AllowHosts`、`AllowSchemes`、`AllowPorts`
- 请求策略:`AllowMethods`
- 重定向:`MaxRedirects`、`NoRedirects`
- 显式授权:`AllowCredentials`、`AllowCustomHostHeader`
- 地址策略:`AllowPrefixes`、`DenyPrefixes`、`AllowCIDRs`、`DenyCIDRs`
- transport/client 限制:`Dialer`、`ClientTimeout`、`MaxResponseHeaderBytes`、`MaxResponseBytes`
`AllowPrefixes` 和 `AllowCIDRs` 会授权额外的地址范围,例如
私有基础设施或本地测试。`DenyPrefixes` 和 `DenyCIDRs`
使地址策略更加严格。Deny 规则会在 allow 规则之前进行评估。
## 致谢
此库受到了以下项目的启发并借鉴了它们的内容:
- [`doyensec/safeurl`](https://github.com/doyensec/safeurl)
- [`daenney/ssrf`](https://github.com/daenney/ssrf)
标签:CISA项目, EVTX分析, Go, Ruby工具, SSRF防御, 开发库, 日志审计, 网络安全, 网络过滤, 隐私保护