Skip to content

feat(csrf): add cross-origin protection middleware#699

Open
yawn wants to merge 17 commits into
tower-rs:mainfrom
yawn:add-csrf-middleware
Open

feat(csrf): add cross-origin protection middleware#699
yawn wants to merge 17 commits into
tower-rs:mainfrom
yawn:add-csrf-middleware

Conversation

@yawn
Copy link
Copy Markdown

@yawn yawn commented May 24, 2026

Ports the CSRF protection scheme introduced in Go 1.25 (described in Filippo Valsorda's blog post) as a new optional csrf feature. The middleware combines Sec-Fetch-Site, an Origin allow-list, and an Origin/Host fallback to reject cross-origin state-changing requests without per-request token state.

See #656 for context.

Ports the CSRF protection scheme introduced in Go 1.25 (described in
Filippo Valsorda's blog post) as a new optional `csrf` feature. The
middleware combines `Sec-Fetch-Site`, an `Origin` allow-list, and an
`Origin`/`Host` fallback to reject cross-origin state-changing requests
without per-request token state.
Copy link
Copy Markdown
Member

@jlizen jlizen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this, @yawn , looks great overall.

Had one small refactor to keep the future a bit simpler.

And then, up to you if you care to add rejection customization, or just document how to use the MapResponse layer for it.

Comment thread tower-http/src/csrf/mod.rs
Comment thread tower-http/src/csrf/mod.rs
Comment thread tower-http/src/csrf/mod.rs
Comment thread tower-http/src/csrf/service.rs Outdated
Comment thread tower-http/src/csrf/service.rs Outdated
Comment thread tower-http/src/csrf/future.rs Outdated
Comment thread tower-http/src/csrf/future.rs Outdated
Comment thread tower-http/src/csrf/future.rs
Comment thread tower-http/src/csrf/service.rs Outdated
Comment thread tower-http/src/csrf/mod.rs Outdated
@yawn
Copy link
Copy Markdown
Author

yawn commented May 25, 2026

One last time from by side: BypassFn is currently private. I don't think it's too much trouble for users to use the middleware as is but wanted to highlight nevertheless.

@jlizen
Copy link
Copy Markdown
Member

jlizen commented May 25, 2026

One last time from by side: BypassFn is currently private. I don't think it's too much trouble for users to use the middleware as is but wanted to highlight nevertheless.

Fine by me, let's keep it opaque for now until we have a reason to open it up.

Copy link
Copy Markdown
Member

@jlizen jlizen left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New changes are great, thanks, the custom rejection closure impl looks good.

The remaining bit is undoing the canonicalize for the comparisons, like we discussed, and optionally tweaking the error type to be more defensive semver.

Comment thread tower-http/src/csrf/layer.rs Outdated
Comment thread tower-http/src/csrf/mod.rs
Copy link
Copy Markdown

@Tremoneck Tremoneck left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just something I noticed when scrolling through. It would however not follow the Blog Post or the Go implementation.

Comment thread tower-http/src/csrf/service.rs
@yawn
Copy link
Copy Markdown
Author

yawn commented May 26, 2026

I'll need a few days for the next round

@yawn
Copy link
Copy Markdown
Author

yawn commented May 30, 2026

All remarks have been addressed and I've added two tracking issues (as proposed): #701 and #702 .

One one more request for clarification: I am adding errors now in the service, not anymore in the default response. This is a bit more logical but this has not really a precedence (as far as I can tell) in the crate. LMK if that works for you.

Addendum: following your style remarks kind is now opaque so it's a bit questionable if making the error available is even worth it. I also did not update the style of the config error - not 100% sure if I should have done so or if the remarks on your end were deliberately scoped to just the protection error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants