ayuhito/safehttp

GitHub: ayuhito/safehttp

safehttp 是一个基于 Go net/http 的防 SSRF HTTP 客户端包装器,在出站请求中拦截内部和特殊用途地址。

Stars: 4 | Forks: 0

# safehttp [![Go Reference](https://pkg.go.dev/badge/github.com/ayuhito/safehttp.svg)](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防御, 开发库, 日志审计, 网络安全, 网络过滤, 隐私保护