ayuhito/safehttp
GitHub: ayuhito/safehttp
Stars: 1 | Forks: 0
# safehttp
[](https://pkg.go.dev/github.com/ayuhito/safehttp)
`safehttp` is an SSRF-resistant wrapper around Go's `net/http` for outbound
requests whose URL is provided by an untrusted source.
Use it when your service fetches URLs from users, webhooks, OAuth metadata,
imported documents, third-party API payloads, or any other source you do not
fully control. It keeps those requests constrained to allowed public
destinations and blocks loopback, RFC1918 networks, Kubernetes, cloud metadata,
and other internal or special-use addresses.
## Defaults
`NewClient()` starts with a public-HTTPS-only configuration.
Requests must use HTTPS, target a public destination, and use port `443`. URL
credentials, custom `Request.Host`, proxies, other schemes or ports, and
internal or special-use IP ranges are blocked.
Redirects are followed by default, but every redirect target is revalidated.
## Install
go get github.com/ayuhito/safehttp
## Usage
Create one client and reuse it.
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()
If the set of valid destinations is known, add a host allowlist.
client, err := safehttp.NewClient(
safehttp.AllowHosts(
"api.github.com",
"uploads.github.com",
"*.githubusercontent.com",
),
safehttp.AllowMethods(http.MethodGet, http.MethodHead),
safehttp.MaxRedirects(3),
safehttp.ClientTimeout(5*time.Second),
safehttp.MaxResponseBytes(8<<20),
)
## Existing Transports
Use `NewTransport` to reuse an existing transport configuration.
base := http.DefaultTransport.(*http.Transport).Clone()
base.MaxIdleConnsPerHost = 32
rt, err := safehttp.NewTransport(base, safehttp.AllowHosts("api.github.com"))
if err != nil {
return err
}
client := &http.Client{Transport: rt}
`safehttp` clones the transport before applying its settings, so the original
transport is not modified. Use `safehttp.Dialer` for custom dialer settings.
Transport settings that bypass safehttp's connection checks or disable TLS
certificate verification are rejected.
## Guard-Only Checks
`NewGuard` exposes validation without constructing an `http.Client`.
guard, err := safehttp.NewGuard(safehttp.AllowHosts("api.github.com"))
if err != nil {
return err
}
if err := guard.CheckRequest(req); err != nil {
return err
}
Use guard-only checks for preflight validation. They do not send the request;
use `NewClient` or `NewTransport` for the outbound HTTP path.
## API Reference
Constructors:
func NewClient(opts ...Option) (*http.Client, error)
func NewTransport(base *http.Transport, opts ...Option) (http.RoundTripper, error)
func NewGuard(opts ...Option) (*Guard, error)
Options:
- destination policy: `AllowSchemes`, `AllowPorts`, `AllowHosts`, `AllowMethods`
- redirects: `MaxRedirects`, `NoRedirects`
- explicit opt-ins: `AllowCredentials`, `AllowCustomHostHeader`
- address policy: `AllowPrefixes`, `DenyPrefixes`, `AllowCIDRs`, `DenyCIDRs`
- transport/client limits: `Dialer`, `ClientTimeout`, `MaxResponseHeaderBytes`, `MaxResponseBytes`
`AllowPrefixes` and `AllowCIDRs` opt in to additional address ranges, for
example private infrastructure or local tests. `DenyPrefixes` and `DenyCIDRs`
make the address policy stricter. Deny rules are evaluated before allow rules.
## Performance
Create one client and reuse it. The added checks are negligible to performance and is safe to use concurrently.
go test -run '^$' -bench Benchmark -benchmem
## Acknowledgements
This library was inspired by and borrows from the following projects:
- [`doyensec/safeurl`](https://github.com/doyensec/safeurl)
- [`daenney/ssrf`](https://github.com/daenney/ssrf)
标签:EVTX分析