一键导入
salvo-csrf
Implement CSRF (Cross-Site Request Forgery) protection using cookie or session storage. Use for protecting forms and state-changing endpoints.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
菜单
Implement CSRF (Cross-Site Request Forgery) protection using cookie or session storage. Use for protecting forms and state-changing endpoints.
用 Codex 或 Claude 帮你安装 复制这段 Prompt,粘贴到 Codex、Claude 或其他助手里,让它检查 Skill 页面并帮你完成安装。
基于 SOC 职业分类
Implement authentication and authorization using JWT, Basic Auth, or custom schemes. Use for securing API endpoints and user management.
Create basic Salvo web applications with handlers, routers, and server setup. Use when starting a new Salvo project or adding basic HTTP endpoints.
Implement caching strategies for improved performance. Use for reducing database load and speeding up responses.
Compress HTTP responses using gzip, brotli, zstd, or deflate. Use for reducing bandwidth and improving load times.
Limit concurrent requests to protect resources. Use for file uploads, expensive operations, and preventing resource exhaustion.
Configure Cross-Origin Resource Sharing (CORS) and security headers. Use for APIs accessed from browsers on different domains.
| name | salvo-csrf |
| description | Implement CSRF (Cross-Site Request Forgery) protection using cookie or session storage. Use for protecting forms and state-changing endpoints. |
| version | 0.94.0 |
| tags | ["security","csrf","protection"] |
[dependencies]
salvo = { version = "0.94.0", features = ["csrf"] }
| Function prefix | Key type | Notes |
|---|---|---|
bcrypt_* | — | No key. Slowest (bcrypt hashing). |
hmac_* | [u8; 32] | Fast. |
aes_gcm_* | [u8; 32] | Authenticated encryption. |
ccp_* | [u8; 32] | ChaCha20Poly1305. |
Each cipher pairs with a store: *_cookie_csrf(...) or *_session_csrf(...). Session variants require a SessionHandler installed earlier in the chain.
use salvo::csrf::{CookieStore, Csrf, BcryptCipher, CsrfDepotExt, FormFinder};
use salvo::http::SecureCookiePolicy;
use salvo::prelude::*;
use serde::Deserialize;
#[derive(Deserialize)]
struct FormData {
csrf_token: String,
message: String,
}
#[handler]
async fn show_form(depot: &mut Depot, res: &mut Response) {
let token = depot.csrf_token().unwrap_or_default();
res.render(Text::Html(format!(
r#"<form method="post">
<input type="hidden" name="csrf_token" value="{token}" />
<input type="text" name="message" />
<button type="submit">Submit</button>
</form>"#
)));
}
#[handler]
async fn handle_form(req: &mut Request, res: &mut Response) {
let data = req.parse_form::<FormData>().await.unwrap();
res.render(format!("Message received: {}", data.message));
}
#[tokio::main]
async fn main() {
let csrf = Csrf::new(
BcryptCipher::new(),
CookieStore::new().secure_cookie_policy(SecureCookiePolicy::Always),
FormFinder::new("csrf_token"),
);
let router = Router::new().hoop(csrf).get(show_form).post(handle_form);
let acceptor = TcpListener::new("0.0.0.0:8080").bind().await;
Server::new(acceptor).serve(router).await;
}
For local HTTP-only examples, bcrypt_cookie_csrf(FormFinder::new(...)) is the shortest constructor. In production behind TLS termination, prefer an explicit CookieStore with .secure(true) or .secure_cookie_policy(SecureCookiePolicy::Always).
use salvo::csrf::{
bcrypt_cookie_csrf, hmac_cookie_csrf, aes_gcm_cookie_csrf, ccp_cookie_csrf,
bcrypt_session_csrf, hmac_session_csrf, aes_gcm_session_csrf, ccp_session_csrf,
FormFinder,
};
let finder = FormFinder::new("csrf_token");
let key = *b"01234567012345670123456701234567"; // 32 bytes
let _ = bcrypt_cookie_csrf(finder.clone());
let _ = hmac_cookie_csrf(key, finder.clone());
let _ = aes_gcm_cookie_csrf(key, finder.clone());
let _ = ccp_cookie_csrf(key, finder.clone());
Session-backed CSRF needs a SessionHandler hooped before the CSRF handler:
use salvo::csrf::{bcrypt_session_csrf, FormFinder};
use salvo::session::{CookieStore, SessionHandler};
use salvo::prelude::*;
#[tokio::main]
async fn main() {
let session = SessionHandler::builder(
CookieStore::new(),
b"secretabsecretabsecretabsecretabsecretabsecretabsecretabsecretab",
).build().unwrap();
let csrf = bcrypt_session_csrf(FormFinder::new("csrf_token"));
let router = Router::new()
.hoop(session) // must come first
.hoop(csrf)
.get(show_form)
.post(handle_form);
let acceptor = TcpListener::new("0.0.0.0:8080").bind().await;
Server::new(acceptor).serve(router).await;
}
use salvo::csrf::{FormFinder, HeaderFinder, JsonFinder};
FormFinder::new("csrf_token"); // application/x-www-form-urlencoded body
HeaderFinder::new("x-csrf-token"); // HTTP header
JsonFinder::new("csrf_token"); // JSON body field
Only FormFinder, HeaderFinder, and JsonFinder exist in salvo::csrf. There is no QueryFinder. Use Csrf::add_finder to accept the token from multiple locations.
use salvo::csrf::CsrfDepotExt;
#[handler]
async fn show_form(depot: &mut Depot, res: &mut Response) {
let token = depot.csrf_token().unwrap_or_default();
res.render(Text::Html(format!(
r#"<form method="post"><input type="hidden" name="csrf_token" value="{token}" /></form>"#
)));
}
A new token is generated on every request; re-render it each time.
let form_finder = FormFinder::new("csrf_token");
let bcrypt_csrf = bcrypt_cookie_csrf(form_finder.clone());
let hmac_csrf = hmac_cookie_csrf(*b"01234567012345670123456701234567", form_finder);
let router = Router::new()
.push(Router::with_hoop(bcrypt_csrf).path("forms").get(show_form).post(handle_form))
.push(Router::with_hoop(hmac_csrf).path("api").get(get_token).post(api_handler));
use salvo::csrf::{HeaderFinder, hmac_cookie_csrf};
let csrf = hmac_cookie_csrf(
*b"01234567012345670123456701234567",
HeaderFinder::new("x-csrf-token"),
);
Client:
fetch('/api', {
method: 'POST',
headers: { 'X-CSRF-Token': token },
body: JSON.stringify(data),
});
SecureCookiePolicy::AutoFromScheme by default. Force secure cookies when TLS is terminated before Salvo.SessionHandler hooped before the CSRF handler, otherwise the store cannot locate a session.salvo-cors, CSRF headers (e.g. x-csrf-token) must be listed in allow_headers.