为什么Rust是认证的理想选择?
\n\n如果您正在用Rust编写Web应用程序,您在安全性方面已经领先一步。Rust不容忍内存错误,这意味着许多漏洞(缓冲区溢出、释放后使用)在编译阶段就被消除了。但编译器无法保护您免受糟糕的认证逻辑的影响。这正是本文要讨论的内容——如何使用现代实践构建Rust中的安全认证。
\n\n在本文中,我们将构建一个完整的认证模块:通过bcrypt进行密码哈希、签发JWT令牌、在Actix-web中进行中间件检查以及防御常见攻击。代码是可运行的——您可以放心地将其用于您的项目。
1. 密码哈希:为什么用bcrypt而不是SHA-256?
\n\n许多初学者会想:“我用SHA-256吧,它又快又可靠。” 这是一个致命的错误。SHA是一种加密哈希函数,但它太快了。攻击者每秒可以尝试数十亿种组合。我们需要一个专门为密码设计的慢速函数。
\n\nbcrypt是黄金标准。它包含“盐值”(salt)和“成本因子”(cost factor),后者可以随着计算能力的增长而增加。
\n\n在Cargo.toml中添加bcrypt
\n[dependencies]\nbcrypt = "0.15"\n\n哈希密码
\nuse bcrypt::{hash, verify, DEFAULT_COST};\n\nfn hash_password(plain: &str) -> Result<String, bcrypt::BcryptError> {\n hash(plain, DEFAULT_COST) // cost = 12 (默认值)\n}\n\nfn verify_password(plain: &str, hashed: &str) -> bool {\n verify(plain, hashed).unwrap_or(false)\n}\n\n请注意:verify会自动从哈希中提取盐值。您无需单独存储盐值——它已经包含在哈希字符串中。这既安全又方便。
2. JWT令牌:如何避免认证失败
\n\n用户输入密码后,我们需要发放一个“通行证”。JWT(JSON Web Token)是一种紧凑且自包含的格式。但魔鬼在细节中:
\n\n- \n
- 不要将密钥存储在代码中。 使用环境变量。 \n
- 设置较短的过期时间。 访问令牌(Access Token)——15-30分钟,刷新令牌(Refresh Token)——7-30天。 \n
- 不要在payload中包含敏感数据。 只包含用户ID和角色。 \n
使用jsonwebtoken实现JWT
\n\nuse jsonwebtoken::{encode, decode, Header, Validation, EncodingKey, DecodingKey};\nuse serde::{Serialize, Deserialize};\nuse chrono::{Utc, Duration};\n\n#[derive(Debug, Serialize, Deserialize)]\npub struct Claims {\n pub sub: String, // 用户ID\n pub exp: usize, // 过期时间戳\n pub iat: usize, // 签发时间\n}\n\npub fn create_token(user_id: &str, secret: &str) -> Result<String, jsonwebtoken::errors::Error> {\n let now = Utc::now();\n let claims = Claims {\n sub: user_id.to_owned(),\n exp: (now + Duration::minutes(30)).timestamp() as usize,\n iat: now.timestamp() as usize,\n };\n encode(&Header::default(), &claims, &EncodingKey::from_secret(secret.as_bytes()))\n}\n\npub fn validate_token(token: &str, secret: &str) -> Result<Claims, jsonwebtoken::errors::Error> {\n let token_data = decode::<Claims>(\n token,\n &DecodingKey::from_secret(secret.as_bytes()),\n &Validation::default(),\n )?;\n Ok(token_data.claims)\n}\n\n3. 整合所有内容:Actix-web + 中间件
\n\n现在,我们将哈希和JWT整合到一个基于Actix-web的完整Web应用程序中。我们将编写一个中间件,用于在每个受保护的请求中检查令牌。
\n\n项目结构
\nsrc/\n├── main.rs\n├── auth.rs # 哈希、JWT\n├── middleware.rs # 令牌检查\n└── handlers.rs #