Rust安全防护库actix-csrf的使用,为Actix Web框架提供CSRF攻击防护与令牌验证功能
// 内容中提供的示例代码:
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
let csrf = Csrf::<StdRng>::new()
.set_cookie(Method::GET, "/login");
App::new().wrap(csrf).service(login_ui).service(login)
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
#[derive(Deserialize)]
struct LoginForm {
csrf_token: CsrfToken,
username: String,
password: String,
}
impl CsrfGuarded for LoginForm {
fn csrf_token(&self) -> &CsrfToken {
&self.csrf_token
}
}
/// Validates a login form that has a CSRF token.
#[post("/login")]
async fn login(form: Csrf<Form<LoginForm>>) -> impl Responder {
// At this point, we have a valid CSRF token, so we can treat the request
// as legitimate.
HttpResponse::Ok().finish()
}
// 完整示例demo:
use actix_csrf::{Csrf, CsrfGuarded, CsrfToken};
use actix_web::{
web::{Form, ServiceConfig},
App, HttpResponse, HttpServer, Responder,
};
use actix_web::http::Method;
use rand::rngs::StdRng;
use serde::Deserialize;
// 定义登录表单结构体
#[derive(Deserialize)]
struct LoginForm {
csrf_token: CsrfToken, // CSRF令牌字段
username: String, // 用户名
password: String, // 密码
}
// 为LoginForm实现CsrfGuarded trait
impl CsrfGuarded for LoginForm {
fn csrf_token(&self) -> &CsrfToken {
&self.csrf_token // 返回CSRF令牌引用
}
}
// 登录UI处理函数
#[get("/login")]
async fn login_ui() -> impl Responder {
HttpResponse::Ok().body(
r#"
<form method="post" action="/login">
<input type="hidden" name="csrf_token" value="{{csrf_token}}">
<input type="text" name="username" placeholder="Username">
<input type="password" name="password" placeholder="Password">
<button type="submit">Login</button>
</form>
"#,
)
}
// 登录处理函数,使用Csrf包装器验证CSRF令牌
#[post("/login")]
async fn login(form: Csrf<Form<LoginForm>>) -> impl Responder {
// 此时CSRF令牌已验证通过,可以安全处理请求
// 这里可以添加实际的登录验证逻辑
println!("Login attempt for user: {}", form.username);
HttpResponse::Ok().body("Login successful!")
}
// 主函数,配置HTTP服务器和CSRF中间件
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
// 创建CSRF中间件实例,使用StdRng作为随机数生成器
let csrf = Csrf::<StdRng>::new()
.set_cookie(Method::GET, "/login"); // 为GET /login请求设置CSRF cookie
App::new()
.wrap(csrf) // 应用CSRF中间件
.service(login_ui) // 注册登录UI服务
.service(login) // 注册登录处理服务
})
.bind(("127.0.0.1", 8080))? // 绑定到本地8080端口
.run()
.await
}
actix-csrf是为actix-web 4.0.0或更新版本提供的CSRF中间件,使用双重提交令牌模式。
此crate尚未经过审计。在生产环境中使用需自行承担风险。
使用方法: 安装中间件是标准的:指定要使用的密码学安全随机数生成器,并声明哪些路径应该设置CSRF cookie以及何时应该验证CSRF cookie。
然后,使用CsrfCookie提取器提取CSRF cookie,并使用作为受保护请求一部分提供的CSRF令牌进行验证。
这只是使用双重提交令牌模式的多种方式之一。
安全考虑: 使用双重提交令牌模式有优点和局限性。强烈建议用户在使用此中间件之前阅读关于CSRF防护的文章。
此crate尝试具有安全的默认设置,用户必须显式禁用纵深防御功能。
许可证: 根据以下任一许可证授权:
- Apache许可证,版本2.0
- MIT许可证
根据您的选择。
贡献: 除非您明确声明,否则任何有意提交包含在作品中的贡献,如Apache-2.0许可证中所定义,应按照上述双重许可,不附加任何额外条款或条件。
Rust安全防护库actix-csrf的使用指南
概述
actix-csrf是为Actix Web框架设计的CSRF(跨站请求伪造)防护库,提供令牌生成、验证和中间件集成功能,帮助开发者有效防范CSRF攻击。
主要功能
- 自动生成和验证CSRF令牌
- 支持Cookie和Header两种令牌存储方式
- 可配置的令牌生命周期和加密选项
- 与Actix Web中间件无缝集成
安装方法
在Cargo.toml中添加依赖:
[dependencies]
actix-csrf = "0.4"
actix-web = "4.0"
基本使用方法
1. 基础配置示例
use actix_csrf::{Csrf, CsrfMiddleware, CsrfConfig};
use actix_web::{web, App, HttpServer, HttpResponse};
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| {
let csrf_config = CsrfConfig::default()
.with_cookie_name("csrf_token")
.with_session_ttl(std::time::Duration::from_secs(3600));
App::new()
.wrap(CsrfMiddleware::new(csrf_config))
.route("/", web::get().to(show_form))
.route("/submit", web::post().to(handle_submit))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
async fn show_form(csrf: Csrf) -> HttpResponse {
let token = csrf.create_token().unwrap();
HttpResponse::Ok().body(format!(
r#"<form action="/submit" method="post">
<input type="hidden" name="csrf_token" value="{}">
<input type="text" name="data">
<button type="submit">Submit</button>
</form>"#,
token
))
}
async fn handle_submit(csrf: Csrf, form: web::Form<Data>) -> HttpResponse {
if csrf.verify_token(&form.csrf_token).is_ok() {
HttpResponse::Ok().body("Form submitted successfully!")
} else {
HttpResponse::BadRequest().body("Invalid CSRF token")
}
}
#[derive(serde::Deserialize)]
struct Data {
csrf_token: String,
data: String,
}
2. 高级配置示例
use actix_csrf::{CsrfMiddleware, CsrfConfig, extraction::CookieExtractor};
use actix_web::cookie::Key;
let config = CsrfConfig::default()
.with_extractor(CookieExtractor::default())
.with_ttl(std::time::Duration::from_secs(1800))
.with_key(Key::generate()); // 使用自定义加密密钥
let middleware = CsrfMiddleware::new(config);
3. 自定义错误处理
use actix_csrf::{CsrfError, Csrf};
use actix_web::{error, HttpResponse};
async fn protected_endpoint(csrf: Csrf) -> Result<HttpResponse, actix_web::Error> {
match csrf.create_token() {
Ok(token) => Ok(HttpResponse::Ok().body(token)),
Err(CsrfError::TokenGeneration) => {
Err(error::ErrorInternalServerError("Token generation failed"))
}
Err(_) => Err(error::ErrorBadRequest("CSRF validation failed")),
}
}
配置选项
with_cookie_name()
: 设置Cookie名称with_ttl()
: 设置令牌有效期with_extractor()
: 设置令牌提取方式(Cookie或Header)with_key()
: 设置加密密钥
注意事项
- 确保在生产环境中使用安全的加密密钥
- 对于API请求,建议使用Header方式传递令牌
- 令牌有效期应根据实际业务需求设置
- 在HTTPS环境下使用以获得最佳安全性
测试验证
建议使用actix-web的测试框架编写单元测试,验证CSRF防护功能正常工作。
这个库为Actix Web应用提供了简单易用的CSRF防护方案,通过中间件集成可以快速为现有应用添加安全防护层。
完整示例代码
use actix_csrf::{Csrf, CsrfMiddleware, CsrfConfig, extraction::CookieExtractor};
use actix_web::{web, App, HttpServer, HttpResponse, cookie::Key};
use serde::Deserialize;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
// 配置CSRF中间件
let csrf_config = CsrfConfig::default()
.with_cookie_name("csrf_token") // 设置cookie名称
.with_extractor(CookieExtractor::default()) // 使用cookie提取器
.with_ttl(std::time::Duration::from_secs(3600)) // 设置令牌有效期1小时
.with_key(Key::generate()); // 生成加密密钥
HttpServer::new(move || {
App::new()
// 添加CSRF中间件
.wrap(CsrfMiddleware::new(csrf_config.clone()))
// 注册路由
.route("/", web::get().to(show_form))
.route("/submit", web::post().to(handle_submit))
.route("/api/token", web::get().to(get_token))
})
.bind("127.0.0.1:8080")?
.run()
.await
}
// 显示包含CSRF令牌的表单
async fn show_form(csrf: Csrf) -> HttpResponse {
match csrf.create_token() {
Ok(token) => {
HttpResponse::Ok().body(format!(
r#"<!DOCTYPE html>
<html>
<head>
<title>CSRF防护示例</title>
</head>
<body>
<h1>表单提交示例</h1>
<form action="/submit" method="post">
<input type="hidden" name="csrf_token" value="{}">
<div>
<label for="data">输入数据:</label>
<input type="text" id="data" name="data">
</div>
<button type="submit">提交</button>
</form>
</body>
</html>"#,
token
))
}
Err(_) => HttpResponse::InternalServerError().body("令牌生成失败"),
}
}
// 处理表单提交
async fn handle_submit(csrf: Csrf, form: web::Form<FormData>) -> HttpResponse {
// 验证CSRF令牌
match csrf.verify_token(&form.csrf_token) {
Ok(_) => {
HttpResponse::Ok().body(format!("表单提交成功! 数据: {}", form.data))
}
Err(_) => {
HttpResponse::BadRequest().body("无效的CSRF令牌")
}
}
}
// API端点 - 获取CSRF令牌
async fn get_token(csrf: Csrf) -> Result<HttpResponse, actix_web::Error> {
match csrf.create_token() {
Ok(token) => Ok(HttpResponse::Ok().body(token)),
Err(_) => Err(actix_web::error::ErrorInternalServerError("令牌生成失败")),
}
}
// 表单数据结构
#[derive(Debug, Deserialize)]
struct FormData {
csrf_token: String,
data: String,
}
这个完整示例展示了如何使用actix-csrf库:
- 配置CSRF中间件并设置相关参数
- 创建包含CSRF令牌的HTML表单
- 验证提交的表单中的CSRF令牌
- 提供API端点获取CSRF令牌
- 包含完整的错误处理机制
要运行此示例,请确保在Cargo.toml中添加了正确的依赖项,并根据需要调整配置参数。