rocket_csrf/README.md

150 lines
3.7 KiB
Markdown
Raw Permalink Normal View History

2020-10-16 22:03:42 +00:00
rocket_csrf
===========
2020-10-16 22:28:31 +00:00
CSRF (Cross-Site Request Forgery) protection for [Rocket](https://rocket.rs)
web framework.
2020-10-16 22:03:42 +00:00
2020-10-16 22:41:03 +00:00
> **WARNING!**
> The implementation is very simple for now and may not be ready for production.
2020-10-17 04:15:08 +00:00
Discussion about CSRF protection in Rocket is
[here](https://github.com/SergioBenitez/Rocket/issues/14).
2020-10-16 22:32:41 +00:00
Table of contents
-----------------
* [Overview](#rocket_csrf)
* [Table of contents](#table-of-contents)
* [Usage](#usage)
2020-10-16 22:35:21 +00:00
* [TODO](#todo)
2020-10-16 22:32:41 +00:00
2020-10-16 22:03:42 +00:00
Usage
-----
2022-07-13 04:52:44 +00:00
Attach [fairing](https://rocket.rs/v0.5-rc/guide/fairings/#fairings) to the Rocket
2020-10-16 22:03:42 +00:00
instance:
```rust
2020-10-16 23:08:58 +00:00
#![feature(decl_macro)]
#[macro_use] extern crate rocket;
#[macro_use] extern crate serde_derive;
2022-07-13 04:49:47 +00:00
use rocket_dyn_templates::Template;
2020-10-16 23:08:58 +00:00
2022-07-13 04:49:47 +00:00
#[launch]
fn rocket() -> _ {
2020-10-16 22:03:42 +00:00
rocket::ignite()
2021-03-06 02:51:02 +00:00
.attach(rocket_csrf::Fairing::default())
2020-10-16 23:08:58 +00:00
.attach(Template::fairing())
.mount("/", routes![new, create])
2020-10-16 22:03:42 +00:00
}
```
2021-03-06 03:30:56 +00:00
You also can configure
2022-07-13 04:52:44 +00:00
[fairing](https://rocket.rs/v0.5-rc/guide/fairings/#fairings):
2021-03-06 03:30:56 +00:00
```rust
2022-07-13 04:49:47 +00:00
#[launch]
fn rocket() -> _ {
2021-03-06 03:30:56 +00:00
rocket::ignite()
.attach(rocket_csrf::Fairing::new(
rocket_csrf::CsrfConfig::default()
.with_cookie_name("foobar")
.with_cookie_len(64)
2021-03-06 03:34:40 +00:00
.with_lifetime(time::Duration::days(3)),
2021-03-06 03:30:56 +00:00
))
.attach(Template::fairing())
.mount("/", routes![new, create])
}
```
2022-07-13 04:52:44 +00:00
Add [guard](https://rocket.rs/v0.5-rc/guide/requests/#request-guards) to any
2020-10-16 22:03:42 +00:00
request where you want to have access to session's CSRF token (e.g. to include
it in forms) or verify it (e.g. to validate form):
```rust
2022-07-13 04:49:47 +00:00
use rocket::form::Form;
2020-10-16 23:08:58 +00:00
use rocket::response::Redirect;
2020-10-16 23:56:13 +00:00
use rocket_csrf::CsrfToken;
2022-07-13 04:49:47 +00:00
use rocket_dyn_templates::Template;
2020-10-16 23:08:58 +00:00
2020-10-16 22:03:42 +00:00
#[get("/comments/new")]
2020-10-17 00:14:03 +00:00
fn new(csrf_token: CsrfToken) -> Template {
2020-10-16 22:03:42 +00:00
// your code
}
#[post("/comments", data = "<form>")]
2020-10-17 00:14:03 +00:00
fn create(csrf_token: CsrfToken, form: Form<Comment>) -> Redirect {
2020-10-16 22:03:42 +00:00
// your code
}
```
Get CSRF token from
2022-07-13 04:52:44 +00:00
[guard](https://rocket.rs/v0.5-rc/guide/requests/#request-guards)
to use it in [templates](https://rocket.rs/v0.5-rc/guide/responses/#templates):
2020-10-16 22:03:42 +00:00
```rust
#[get("/comments/new")]
2020-10-17 00:14:03 +00:00
fn new(csrf_token: CsrfToken) -> Template {
2020-10-18 07:29:55 +00:00
let authenticity_token: &str = csrf_token.authenticity_token();
2020-10-16 22:03:42 +00:00
// your code
}
```
Add CSRF token to your HTML forms in
2022-07-13 04:52:44 +00:00
[templates](https://rocket.rs/v0.5-rc/guide/responses/#templates):
2020-10-16 22:03:42 +00:00
```html
<form method="post" action="/comments">
2020-10-17 00:14:03 +00:00
<input type="hidden" name="authenticity_token" value="{{ authenticity_token }}"/>
2020-10-16 22:03:42 +00:00
<!-- your fields -->
</form>
```
Add attribute `authenticity_token` to your
2022-07-13 04:52:44 +00:00
[forms](https://rocket.rs/v0.5-rc/guide/requests/#forms):
2020-10-16 22:03:42 +00:00
```rust
#[derive(FromForm)]
struct Comment {
authenticity_token: String,
// your attributes
}
```
2022-07-13 04:52:44 +00:00
Validate [forms](https://rocket.rs/v0.5-rc/guide/requests/#forms) to have valid
2020-10-16 22:03:42 +00:00
authenticity token:
```rust
#[post("/comments", data = "<form>")]
2020-10-17 00:14:03 +00:00
fn create(csrf_token: CsrfToken, form: Form<Comment>) -> Redirect {
if let Err(_) = csrf_token.verify(&form.authenticity_token) {
2020-10-16 23:08:58 +00:00
return Redirect::to(uri!(new));
2020-10-16 22:03:42 +00:00
}
// your code
}
```
2020-10-16 22:35:21 +00:00
2020-10-16 23:08:58 +00:00
See the complete code in [minimal example](examples/minimal).
2020-10-16 22:35:21 +00:00
TODO
----
* [ ] Add fairing to verify all requests as an option.
2022-07-13 04:52:44 +00:00
* [ ] Add [data guard](https://api.rocket.rs/v0.5-rc/rocket/data/trait.FromData.html) to verify forms with a guard.
2020-10-16 22:35:21 +00:00
* [ ] Add helpers to render form field.
* [ ] Add helpers to add HTML meta tags for Ajax with `X-CSRF-Token` header.
* [ ] Verify `X-CSRF-Token` header.
* [ ] Use authenticity token encryption from [Ruby on Rails](https://github.com/rails/rails/blob/v6.0.3.4/actionpack/lib/action_controller/metal/request_forgery_protection.rb).
* [ ] Allow to configure CSRF protection (CSRF token byte length, cookie name, etc.).
* [ ] Set cookie to expire with session.