This spawned from the discussion in #197
This PR replaces all of our existing CSRF machinery (axum_csrf plus our silverfish-middleware-csrf crate) with tower-sec-fetch instead.
The high-level idea is to avoid the classic approaches for CSRF protections (i.e. using cookies and/or random tokens), and to instead rely entirely (or almost entirely) on the Sec-Fetch-* family of request headers. For modern browsers, this protects against CSRF attacks just as well as the classic approaches, but is much simpler to implement (and therefore leaves a lot less room for security vulnerabilities). For more reading, I found these articles really helpful, and used them to guide my implementation:
I used tower-sec-fetch, which-- as the name implies-- gives us a tower layer to check the Sec-Fetch-* headers! But I ended up adding a custom SecFetchAuthorizer too, to tweak the behavior:
Finally, I ripped out all the old CSRF stuff, which was really satisfying! axum_csrf is gone, our custom AuthenticForm / AuthenticMultipart extractors are gone, the entire silverfish-middleware-csrf crate is gone, csrf-salt in the config is gone, all the CSRF token form inputs are gone.
This spawned from the discussion in https://codeberg.org/conjured/silverfish/issues/197
This PR replaces all of our existing [CSRF](https://developer.mozilla.org/en-US/docs/Web/Security/Attacks/CSRF) machinery ([`axum_csrf`](https://crates.io/crates/axum_csrf) plus our `silverfish-middleware-csrf` crate) with [`tower-sec-fetch`](https://crates.io/crates/tower-sec-fetch) instead.
The high-level idea is to avoid the classic approaches for CSRF protections (i.e. using cookies and/or random tokens), and to instead rely entirely (or almost entirely) on the [`Sec-Fetch-*`](https://developer.mozilla.org/en-US/docs/Glossary/Fetch_metadata_request_header) family of request headers. For modern browsers, this protects against CSRF attacks just as well as the classic approaches, but is _much_ simpler to implement (and therefore leaves a lot less room for security vulnerabilities). For more reading, I found these articles really helpful, and used them to guide my implementation:
- https://blog.miguelgrinberg.com/post/csrf-protection-without-tokens-or-hidden-form-fields
- https://words.filippo.io/csrf/
I used [`tower-sec-fetch`](https://github.com/MatteoJoliveau/tower-sec-fetch), which-- as the name implies-- gives us a `tower` layer to check the `Sec-Fetch-*` headers! But I ended up adding a custom [`SecFetchAuthorizer`](https://docs.rs/tower-sec-fetch/0.1.2/tower_sec_fetch/trait.SecFetchAuthorizer.html) too, to tweak the behavior:
- Reject `Sec-Fetch-Site: same-site` requests (redundant if this PR is merged upstream: https://github.com/MatteoJoliveau/tower-sec-fetch/pull/5)
- Check by origin as a fallback (if the `Origin` header is set but the `Sec-Fetch-Site` header is not)
Finally, I ripped out _all_ the old CSRF stuff, which was really satisfying! `axum_csrf` is gone, our custom `AuthenticForm` / `AuthenticMultipart` extractors are gone, the entire `silverfish-middleware-csrf` crate is gone, `csrf-salt` in the config is gone, all the CSRF token form inputs are gone.