Library to Provide a CSRF (Cross-Site Request Forgery) protection layer.
Add it to Axums via layer. ```rust
async fn main() { let config = //load your config here. let poll = init_pool(&config).unwrap();
let session_config = SqlxSessionConfig::default()
.with_database("test")
.with_table_name("test_table");
// build our application with some routes
let app = Router::new()
.route("/greet", get(greet))
.route("/check_key", post(check_key))
.layer(CsrfLayer::new(CsrfConfig::default()));
// run it
let addr = SocketAddr::from(([127, 0, 0, 1], 3000));
axum::Server::bind(&addr)
.serve(app.into_make_service())
.await
.unwrap();
} ```
If you already have an encryption key for private cookies, build the layer a different way: ```rust let cookiekey = cookie::Key::generate(); // or from()/derivefrom()
let csrflayer = CsrfLayer::build() .config(CsrfConfig::default()) .key(cookiekey) .finish();
let app = Router::new() // ... .layer(csrf_layer); ```
Get the Hash for the Form to insert into the html for return. ```rust async fn greet(token: CsrfToken) -> impl IntoResponse { let keys = Keys { authenticitytoken: token.authenticitytoken(), }
//we must return the token so that into_response will run and add it to our response cookies.
(token, HtmlTemplate(keys))
} ```
Insert it in the html form ```html
```
Add the Attribute to your form return structs ```rust
struct Keys { authenticity_token: String, // your attributes } ```
Validate the CSRF Key
rust
async fn check_key(token: CsrfToken, Form(payload): Form<Keys>,) -> &'static str {
if let Err(_) = token.verify(&payload.authenticity_token) {
"Token is invalid"
} else {
"Token is Valid lets do stuff!"
}
}
If you want to Prevent Post Replay Attacks then you should use a Session Storage method. you store the hash in the server side session store as well as send it with the form. when they post the data you would check the hash of the form first and then against the internal session data 2nd. After the 2nd hash is valid you would then remove the hash from the session. This prevents replay attacks and ensure no data was munipulated. If you need a Session database I would suggest using Axumdatabasesessions
Changes using axumdatabasesessions. ```rust async fn greet(token: CsrfToken, sessions: AxumSession) -> impl IntoResponse { let authenticitytoken = token.authenticitytoken(); session.set("authenticitytoken", authenticitytoken.clone()).await;
let keys = Keys {
authenticity_token,
}
//we must return the token so that into_response will run and add it to our response cookies.
(token, HtmlTemplate(keys))
} ```
Validate the CSRF Key and Validate for Post Replay attacks
```rust
async fn checkkey(token: CsrfToken, sessions: AxumSession, Form(payload): Form
if let Err(_) = token.verify(&payload.authenticity_token) {
"Token is invalid"
} else if let Err(_) = token.verify(&authenticity_token) {
"Modification of both Cookie/token OR a replay attack occured"
} else {
// we remove it to only allow one post per generated token.
session.remove("authenticity_token").await;
"Token is Valid lets do stuff!"
}
} ```
If you need help with this library please go to our Discord Group