Skip to main content

Crate ssrf_guard

Crate ssrf_guard 

Source
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/24 or 2001: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 Fetcher may connect to, and how long it may take. Build one with Policy::builder.
PolicyBuilder
Builds a Policy. Start with Policy::builder, which starts from the defaults, and finish with build.
Request
An HTTP request for Fetcher::send.
Response
The response at the end of a redirect chain.
StatusCode
An HTTP status code (status-code in 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. Fetcher uses the system resolver unless you give it another one with Fetcher::with_resolver.

Functions§

is_public
Whether ip is an address a fetch may reach under the built-in rules.