pub struct HttpAclMiddleware { /* private fields */ }Expand description
A reqwest middleware that enforces an HttpAcl.
On each request, checks (in order) the scheme, method, host or IP, port, headers,
URL path, and finally any custom ValidateFn, returning
reqwest_middleware::Error::Middleware on the first denial. This alone only
covers the request as originally built: attach Self::dns_resolver to the
Client as well, so domains are checked against the ACL as they resolve, and
Self::redirect_policy, so redirect targets are checked too. See the crate-level
documentation for a full example wiring all three together.
Implementations§
Source§impl HttpAclMiddleware
impl HttpAclMiddleware
Sourcepub fn new(acl: HttpAcl) -> Self
pub fn new(acl: HttpAcl) -> Self
Create a new HTTP ACL middleware from an already-built HttpAcl.
Sourcepub fn dns_resolver(&self) -> Arc<HttpAclDnsResolver> ⓘ
pub fn dns_resolver(&self) -> Arc<HttpAclDnsResolver> ⓘ
Create a DNS resolver that enforces the ACL, using getaddrinfo to actually
resolve hostnames.
Set via Client::builder().dns_resolver(...). Without this, a domain that
resolves to a denied or non-global IP (the classic SSRF vector) is never
checked, since HttpAclMiddleware only ever sees the request as built, not
the address it eventually connects to.
Sourcepub fn with_dns_resolver(
&self,
dns_resolver: Arc<dyn Resolve>,
) -> Arc<HttpAclDnsResolver> ⓘ
pub fn with_dns_resolver( &self, dns_resolver: Arc<dyn Resolve>, ) -> Arc<HttpAclDnsResolver> ⓘ
Same as Self::dns_resolver, but delegating actual resolution to a custom
Resolve implementation instead of getaddrinfo.
Sourcepub fn redirect_policy(&self) -> Policy
pub fn redirect_policy(&self) -> Policy
Create a redirect::Policy that enforces the ACL on every redirect hop.
§Why this is necessary
HttpAclMiddleware only validates the request it is given. By default reqwest
follows HTTP redirects internally (up to 10 hops) before control ever returns to
the middleware chain, so a server an allowed host redirects to - e.g. a 302 to
http://169.254.169.254/ - is never re-checked against the ACL. Set this policy
on the Client (in addition to Self::dns_resolver) to close that gap:
let client = reqwest::Client::builder()
.dns_resolver(middleware.dns_resolver())
.redirect(middleware.redirect_policy())
.build()
.unwrap();Uses a maximum of 10 redirects, matching reqwest’s own default. Use
Self::redirect_policy_with_max to customise this.
§Limitations
Only the scheme, host/IP, port, and URL path of each redirect target can be
checked this way - reqwest’s redirect policy does not expose the headers or
body of the redirected request, so denied headers, denied bodies, and any custom
validate_fn are not re-evaluated per hop.
Sourcepub fn redirect_policy_with_max(&self, max_redirects: usize) -> Policy
pub fn redirect_policy_with_max(&self, max_redirects: usize) -> Policy
Same as Self::redirect_policy, but with a custom maximum number of redirects.
Trait Implementations§
Source§impl Clone for HttpAclMiddleware
impl Clone for HttpAclMiddleware
Source§fn clone(&self) -> HttpAclMiddleware
fn clone(&self) -> HttpAclMiddleware
1.0.0 (const: unstable) · Source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source. Read moreSource§impl Debug for HttpAclMiddleware
impl Debug for HttpAclMiddleware
Source§impl Middleware for HttpAclMiddleware
impl Middleware for HttpAclMiddleware
Source§fn handle<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
req: Request,
extensions: &'life1 mut Extensions,
next: Next<'life2>,
) -> Pin<Box<dyn Future<Output = Result<Response, Error>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
fn handle<'life0, 'life1, 'life2, 'async_trait>(
&'life0 self,
req: Request,
extensions: &'life1 mut Extensions,
next: Next<'life2>,
) -> Pin<Box<dyn Future<Output = Result<Response, Error>> + Send + 'async_trait>>where
Self: 'async_trait,
'life0: 'async_trait,
'life1: 'async_trait,
'life2: 'async_trait,
next.run(req, extensions). Read more