#csrf #tide #security #request-headers #query-parameters #csrf-token

tide-csrf

Cross-Site Request Forgery (CSRF) protection middleware for Tide

2 releases

0.1.1 Sep 6, 2021
0.1.0 Aug 12, 2021

#900 in HTTP server

Download history 2/week @ 2024-03-26 32/week @ 2024-04-02

107 downloads per month

MIT/Apache

40KB
580 lines

tide-csrf

Build Status Latest version Documentation License Contributor Covenant

Cross-Site Request Forgery (CSRF) protection middleware for Tide.

This crate provides middleware that helps you defend against CSRF attacks. The middleware generates a CSRF cookie and adds it to your Tide response, and then generates a CSRF token and makes it available to your Tide request. In your HTML, you then arrange for the CSRF token to be returned to the server on subsequent requests, either in a request header, a query parameter, or a form field. The middleware then verifies that a CSRF token is present and valid whenever a request is received for a protected method.

Usage

Add this to your Cargo.toml:

[dependencies]
tide-csrf = "0.1"

Example

use tide_csrf::{self, CsrfRequestExt};

let mut app = tide::new();

app.with(tide_csrf::CsrfMiddleware::new(
    b"we recommend you use std::env::var(\"TIDE_SECRET\").unwrap().as_bytes() instead of a fixed value"
));

// This is an unprotected method and does not require a CSRF token
// (but will set the CSRF cookie).
app.at("/").get(|req: tide::Request<()>| async move {
    // Note that here we are simply returning the token in a string, but
    // in a real application you need to arrange for the token to appear
    // in the request to the server.
    Ok(format!(
        "CSRF token is {}; you should return that in header {}, or query param {}, or a form field named {}",
        req.csrf_token(),
        req.csrf_header_name(),
        req.csrf_query_param(),
        req.csrf_field_name()
    ))
});

// This is a protected method and will only allow the request to
// make it to the handler if the CSRF token is present in the
// request. Otherwise an HTTP status of `Forbidden` will be
// returned and the handler will *not* be called.
app.at("/").post(|req: tide::Request<()>| async move {
   Ok("Getting this far means that the CSRF token was present in the request.")
});

Protected Methods

By default, this middleware protects only those HTTP methods that might mutate state on the server. Those "unsafe" methods are POST, PUT, PATCH, and DELETE. The remaining methods -- GET, HEAD, etc. -- are not protected by default. This limits the performance impact of the middleware on your application.

However, if your application does mutate state in those "safe" methods then you need to set the list of protected methods to include those other methods.

Note that protecting GET may create a "chicken and egg" situation where you have no way to return the CSRF cookie and token to a caller for them to return back to you in a subsequent request! In general, the default list of methods is the correct one and you should ensure that the "safe" methods are in fact truly safe and do not perform any mutations.

Performance Considerations

This middleware adds a CSRF cookie to every request and looks for a matching CSRF token when processing a request for a protected method. The CSRF token can be returned in an HTTP header, the URL query string, or an application/x-www-form-urlencoded form body. The token is searched for in that order and the search will be terminated as soon as the token is found.

The most efficient place to search for the token is in an HTTP header and that mechanism should be preferred if you have the ability to set headers in the request. The query string is a good option if you cannot set HTTP headers.

Using form fields is the least efficient way to return the CSRF token because the middleware has to read and deserialize the entire request body in order to see if the token is present, and then make a full, in-memory copy of the body available to your application. Tide request bodies are normally streamed to the application, so performing this extra deserialization and memory copy step is quite expensive relative to the normal request flow.

For this reason, the middleware searches the form fields last and only considers application/x-www-form-urlencoded requests; multipart/form-data bodies, which may contain large binary payloads, are not searched. If you need to protect multipart/form-data requests then you should return the CSRF token in an HTTP header or the query string.

Conduct

This project adheres to the Contributor Covenant Code of Conduct. This describes the minimum behavior expected from all contributors.

License

Licensed under either of

at your option.

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Dependencies

~13–25MB
~377K SLoC