csrf only.Expand description
Modern protection against cross-site request forgery (CSRF) attacks.
This middleware implements the CSRF protection scheme introduced in Go 1.25
and described in Filippo Valsorda’s blog post. It relies on the
Sec-Fetch-Site and Origin request headers and requires no
per-request token state.
Requests are allowed if any of the following hold:
- The method is
GET,HEAD, orOPTIONS. - The
Originheader byte-for-byte matches an allow-listed trusted origin. Sec-Fetch-Siteissame-originornone.- Neither
Sec-Fetch-SitenorOriginis present. - The
Origin’s authority (host and any port) matches the request’s effective host byte-for-byte (the request-target authority if present, elseHost).
Rejected requests receive a 403 Forbidden response. The originating
ProtectionError is attached to the response’s extensions — on every
rejection, including those from a custom builder — so surrounding layers can
distinguish explicit cross-origin rejections from conservative fallback
rejections (e.g. requests from old browsers without Sec-Fetch-Site). Use
CsrfLayer::with_rejection_response
to replace the rejection response with a custom builder.
§Deployment caveat
The middleware trusts whatever Origin and Host reach it. Reverse proxies
and load balancers that rewrite Host (e.g. to an internal hostname) or
strip Origin silently degrade the protection: the Origin/Host
fallback can no longer match, and Sec-Fetch-Site becomes the only
remaining line of defense. Configure intermediaries to forward both headers
unchanged.
§Example
use bytes::Bytes;
use http::{Request, Response, StatusCode};
use http_body_util::Full;
use tower::{Service, ServiceExt, ServiceBuilder, service_fn, BoxError};
use tower_http::csrf::CsrfLayer;
async fn handle(_: Request<Full<Bytes>>) -> Result<Response<Full<Bytes>>, BoxError> {
Ok(Response::new(Full::default()))
}
let layer = CsrfLayer::new()
.add_trusted_origin("https://example.com")?;
let mut service = ServiceBuilder::new()
.layer(layer)
.service_fn(handle);
// Safe methods always pass.
let request = Request::builder()
.method("GET")
.uri("/")
.body(Full::default())
.unwrap();
let response = service.ready().await?.call(request).await?;
assert_eq!(response.status(), StatusCode::OK);
// Cross-site POSTs are blocked.
let request = Request::builder()
.method("POST")
.uri("/")
.header("host", "example.com")
.header("sec-fetch-site", "cross-site")
.body(Full::default())
.unwrap();
let response = service.ready().await?.call(request).await?;
assert_eq!(response.status(), StatusCode::FORBIDDEN);
Structs§
- Csrf
- Middleware that enforces cross-origin request forgery (CSRF) protection.
- Csrf
Layer - Layer that applies the
Csrfmiddleware. - Default
Response ForProtection Error - Default
ResponseForProtectionErrorused byCsrfLayer::new. - Protection
Error - Reason a request was rejected by
Csrf. - Response
Future - Response future for
Csrf.
Enums§
- Config
Error - Errors that can occur while configuring
CsrfLayer. - Protection
Error Kind - The category of a
ProtectionError.
Traits§
- Response
ForProtection Error - Builds the response returned by
Csrfwhen a request fails CSRF protection.