Expand description

This crate provides a CSRF middleware to help protect endpoints.

The primary entry point is through CsrfMiddleware and the Csrf extractor, which together provides a stateless CSRF mitigation implementation through a double-submit cookie pattern.

CsrfMiddleware uses the double-submit cookie pattern as the mechanism for CSRF mitigation. Generally speaking, the double-submit process is as follows:

  • User submits a request for a resource that will directly send a CSRF token (such as a login form). The server will respond with a Set-Cookie header containing the CSRF token.
  • The user then submits a request that contains the CSRF token, either through a custom header or in the request itself. This results in the client sending the CRSF token twice: once as a cookie and once as a header or as part of the request itself.
  • The server then validates if the CSRF value in the request is the same as the CSRF value in the cookie. If it is, the request is allowed to proceed.

This is why this process is known as a double-submit: You submit the CSRF value to a CSRF protected endpoint in two different ways. For more information why this works, see the Owasp Cheat Sheet on Double-Submit Cookies.

Note that the double submit pattern has its own weaknesses. While it is a stateless pattern, it is only effective if all subdomains are fully secured and only accept HTTPS connections. Additionally, XSS attacks will render all CSRF mitigation techniques ineffective!

Usage

Using this middleware is simple. You just need to configure which endpoints should set a CSRF cookie, and then use Csrf trait to transparently validate the cookie.

use actix_csrf::CsrfMiddleware;
use rand::rngs::StdRng;

let csrf = CsrfMiddleware::<StdRng>::new().set_cookie(Method::GET, "/login");
let app = App::new().wrap(csrf);

Endpoints that set a CSRF cookie can either access the CSRF token through the CrsfToken extractor, or through JavaScript that accesses the cookie if HttpOnly is disabled. For example, to access the CSRF token in the responder:

use actix_csrf::extractor::CsrfToken;

#[get("/login")]
async fn login_ui(token: CsrfToken) -> impl Responder {
    // `token` will contain the csrf value that will be sent as a cookie.
    // Render something with the token, e.g. as a hidden input in a form.
    println!("csrf value that will be set is: {:?}", token.get());
    HttpResponse::Ok().finish()
}

Then, endpoints that require a CSRF cookie must validate the CSRF token in the request. This can be done by manually accessing the cookie, or by using the Csrf extractor, which will validate the CSRF token for you if CsrfGuarded is implemented in the underlying struct.

use actix_csrf::extractor::{Csrf, CsrfGuarded, CsrfToken};

#[derive(serde::Deserialize)]
struct LoginForm { csrf_token: CsrfToken }

impl CsrfGuarded for LoginForm {
    fn csrf_token(&self) -> &CsrfToken {
        &self.csrf_token
    }
}

#[post("/login")]
async fn login(form: Csrf<Form<LoginForm>>) -> impl Responder {
    // The CSRF token is valid, so the request can proceed.

    // ...Do other stuff here...

    HttpResponse::Ok().finish()
}

For simple but complete examples, see the examples directory.

Defense-in-depth Measures

By default, this middleware multiple various defense-in-depth measures, such as using a __Host- prefix, requiring the cookie to be secure, HttpOnly, and SameSite=Strict. However, it is always recommended to implement more; suggestions are deferred to the Owasp Cheat Sheet.

Modules

Contains various extractors related to CSRF tokens.

Structs

CSRF middleware to manage CSRF cookies and tokens.

Enums

Internal errors that can happen when processing CSRF tokens.

Traits

Used to generate CSRF tokens.