Expand description
Fetch user-supplied URLs from a server without letting them reach your private network.
When a server fetches a URL someone else gave it (a webhook, a link
preview, an uptime check), the URL can point at 127.0.0.1, at the cloud
metadata service on 169.254.169.254, or at a name that resolves to one
of them.
A Fetcher resolves every hop itself and refuses the whole name if any
address is loopback, private, link-local or otherwise not public
(is_public has the list, IPv6 spellings included). It then connects
only to the addresses it checked. A DNS answer that changes afterwards
changes nothing. Redirects are followed by hand and checked again, a
redirect to another origin goes without the headers and body you set,
proxies from the environment are ignored, and one timeout covers the
whole chain.
use ssrf_guard::{Fetcher, Policy};
let fetcher = Fetcher::new(Policy::default());
let resp = fetcher.get("https://example.com/").await?;
println!("{} from {:?}", resp.status(), resp.remote_addr());
let body = resp.text().await?;A redirect to http://localhost/ or to a name that resolves to 10.1.2.3
fails with Error::Denied. Fetcher::connect does the same checks
for a plain TCP connection, and Fetcher::resolve for anything else
you connect yourself.
To refuse more, such as your own servers’ public addresses, add blocks
with PolicyBuilder::deny. To let something through that the list refuses,
such as loopback in tests, use PolicyBuilder::allow.
§Platform notes
Needs a tokio runtime. TLS is rustls with the platform verifier, which
checks certificates against the operating system’s trust store. On
Linux that needs a CA bundle installed (ca-certificates on Debian and
Alpine), which slim container images often leave out. TLS session
resumption is off. A server can’t use session tickets to tie one
caller’s fetches to another’s. HTTP/1.1 only.
The system resolver blocks a thread per lookup, and the policy’s timeout
can’t stop it. See PolicyBuilder::timeout.
The checks run on the addresses this process connects to. They can’t see past a NAT64 gateway or a VPN that routes public addresses somewhere private, and they don’t stop a public server you fetch from doing whatever it likes with the request.
Modules§
- header
- HTTP header types
Structs§
- Bytes
- A cheaply cloneable and sliceable chunk of contiguous memory.
- Cidr
- An address block, such as
203.0.113.0/24or2001:db8::/32. A bare address parses as a block of one. - Fetcher
- Fetches URLs, and opens TCP connections, under a
Policy. - Method
- The Request Method (VERB)
- Policy
- What a
Fetchermay connect to, and how long it may take. Build one withPolicy::builder. - Policy
Builder - Builds a
Policy. Start withPolicy::builder, which starts from the defaults, and finish withbuild. - Request
- An HTTP request for
Fetcher::send. - Response
- The response at the end of a redirect chain.
- Status
Code - An HTTP status code (
status-codein RFC 9110 et al.). - Url
- A parsed URL record.
Enums§
- Error
- Why a fetch or connect didn’t happen, or didn’t finish.
Traits§
- Resolve
- Turns a host name into addresses.
Fetcheruses the system resolver unless you give it another one withFetcher::with_resolver.
Functions§
- is_
public - Whether
ipis an address a fetch may reach under the built-in rules.