# 性能优化和安全加固指南 ## 📈 性能优化 ### 1. Rust应用优化 #### 编译优化 ```toml # Cargo.toml [profile.release] opt-level = 3 # 最高优化级别 lto = true # 链接时优化 codegen-units = 1 # 单个代码生成单元 panic = 'abort' # 减少二进制大小 strip = true # 移除调试符号 ``` #### 内存优化 ```rust // src/config/performance.rs use std::sync::Arc; use tokio::sync::RwLock; pub struct PerformanceConfig { pub max_connections: usize, pub connection_timeout: u64, pub request_timeout: u64, pub worker_threads: usize, pub max_blocking_threads: usize, } impl Default for PerformanceConfig { fn default() -> Self { Self { max_connections: 1000, connection_timeout: 30, request_timeout: 30, worker_threads: num_cpus::get(), max_blocking_threads: 512, } } } // 连接池优化 pub fn optimize_database_pool() -> sqlx::SqlitePool { sqlx::sqlite::SqlitePoolOptions::new() .max_connections(20) .min_connections(5) .acquire_timeout(std::time::Duration::from_secs(30)) .idle_timeout(std::time::Duration::from_secs(600)) .max_lifetime(std::time::Duration::from_secs(1800)) .build("sqlite://production.db") .expect("Failed to create database pool") } ``` #### 异步优化 ```rust // 使用批量操作减少数据库调用 pub async fn batch_create_users( pool: &SqlitePool, users: Vec, ) -> Result, sqlx::Error> { let mut tx = pool.begin().await?; let mut created_users = Vec::new(); for user in users { let created_user = sqlx::query_as!( User, "INSERT INTO users (username, email, password_hash) VALUES (?, ?, ?) RETURNING *", user.username, user.email, user.password_hash ) .fetch_one(&mut *tx) .await?; created_users.push(created_user); } tx.commit().await?; Ok(created_users) } // 使用流式处理大量数据 use futures::StreamExt; pub async fn stream_users(pool: &SqlitePool) -> impl Stream> { sqlx::query_as!(User, "SELECT * FROM users") .fetch(pool) } ``` ### 2. 数据库优化 #### SQLite优化配置 ```sql -- 性能优化设置 PRAGMA journal_mode = WAL; -- 写前日志模式 PRAGMA synchronous = NORMAL; -- 平衡性能和安全 PRAGMA cache_size = 1000000; -- 1GB缓存 PRAGMA temp_store = memory; -- 临时表存储在内存 PRAGMA mmap_size = 268435456; -- 256MB内存映射 PRAGMA optimize; -- 优化查询计划 -- 索引优化 CREATE INDEX IF NOT EXISTS idx_users_email ON users(email); CREATE INDEX IF NOT EXISTS idx_users_username ON users(username); CREATE INDEX IF NOT EXISTS idx_users_created_at ON users(created_at); CREATE INDEX IF NOT EXISTS idx_users_role ON users(role); -- 复合索引 CREATE INDEX IF NOT EXISTS idx_users_role_created ON users(role, created_at); CREATE INDEX IF NOT EXISTS idx_users_active_email ON users(is_active, email) WHERE is_active = 1; ``` #### 查询优化 ```rust // 使用预编译语句 pub struct OptimizedQueries { find_user_by_email: sqlx::query::Query<'static, sqlx::Sqlite, sqlx::sqlite::SqliteArguments<'static>>, find_users_paginated: sqlx::query::Query<'static, sqlx::Sqlite, sqlx::sqlite::SqliteArguments<'static>>, } impl OptimizedQueries { pub fn new() -> Self { Self { find_user_by_email: sqlx::query_as!( User, "SELECT * FROM users WHERE email = ? LIMIT 1" ), find_users_paginated: sqlx::query_as!( User, "SELECT * FROM users ORDER BY created_at DESC LIMIT ? OFFSET ?" ), } } } // 使用连接查询减少数据库往返 pub async fn get_user_with_profile( pool: &SqlitePool, user_id: i64, ) -> Result { sqlx::query_as!( UserWithProfile, r#" SELECT u.id, u.username, u.email, u.created_at, p.bio, p.avatar_url, p.location FROM users u LEFT JOIN user_profiles p ON u.id = p.user_id WHERE u.id = ? "#, user_id ) .fetch_one(pool) .await } ``` ### 3. 缓存策略 #### Redis缓存实现 ```rust // src/cache/redis.rs use redis::{Client, Connection, RedisResult}; use serde::{Deserialize, Serialize}; use std::time::Duration; pub struct RedisCache { client: Client, } impl RedisCache { pub fn new(redis_url: &str) -> RedisResult { let client = Client::open(redis_url)?; Ok(Self { client }) } pub async fn get(&self, key: &str) -> RedisResult> where T: for<'de> Deserialize<'de>, { let mut conn = self.client.get_async_connection().await?; let value: Option = redis::cmd("GET").arg(key).query_async(&mut conn).await?; match value { Some(json) => Ok(Some(serde_json::from_str(&json).map_err(|_| { redis::RedisError::from((redis::ErrorKind::TypeError, "JSON parse error")) })?)), None => Ok(None), } } pub async fn set(&self, key: &str, value: &T, ttl: Duration) -> RedisResult<()> where T: Serialize, { let mut conn = self.client.get_async_connection().await?; let json = serde_json::to_string(value).map_err(|_| { redis::RedisError::from((redis::ErrorKind::TypeError, "JSON serialize error")) })?; redis::cmd("SETEX") .arg(key) .arg(ttl.as_secs()) .arg(json) .query_async(&mut conn) .await } } // 缓存装饰器 pub async fn cached_get_user( cache: &RedisCache, pool: &SqlitePool, user_id: i64, ) -> Result { let cache_key = format!("user:{}", user_id); // 尝试从缓存获取 if let Ok(Some(user)) = cache.get::(&cache_key).await { return Ok(user); } // 从数据库获取 let user = get_user_by_id(pool, user_id).await?; // 存入缓存 let _ = cache.set(&cache_key, &user, Duration::from_secs(300)).await; Ok(user) } ``` #### 内存缓存 ```rust // src/cache/memory.rs use std::collections::HashMap; use std::sync::Arc; use std::time::{Duration, Instant}; use tokio::sync::RwLock; pub struct MemoryCache { data: Arc>>>, default_ttl: Duration, } struct CacheEntry { value: T, expires_at: Instant, } impl MemoryCache { pub fn new(default_ttl: Duration) -> Self { Self { data: Arc::new(RwLock::new(HashMap::new())), default_ttl, } } pub async fn get(&self, key: &str) -> Option { let data = self.data.read().await; if let Some(entry) = data.get(key) { if entry.expires_at > Instant::now() { return Some(entry.value.clone()); } } None } pub async fn set(&self, key: String, value: T) { let expires_at = Instant::now() + self.default_ttl; let entry = CacheEntry { value, expires_at }; let mut data = self.data.write().await; data.insert(key, entry); } pub async fn cleanup_expired(&self) { let mut data = self.data.write().await; let now = Instant::now(); data.retain(|_, entry| entry.expires_at > now); } } ``` ### 4. HTTP优化 #### 连接池和超时配置 ```rust // src/server/config.rs use axum::http::HeaderValue; use tower::ServiceBuilder; use tower_http::{ compression::CompressionLayer, cors::CorsLayer, timeout::TimeoutLayer, trace::TraceLayer, }; pub fn create_optimized_app() -> Router { Router::new() .layer( ServiceBuilder::new() .layer(TraceLayer::new_for_http()) .layer(CompressionLayer::new()) .layer(TimeoutLayer::new(Duration::from_secs(30))) .layer( CorsLayer::new() .allow_origin("https://yourdomain.com".parse::().unwrap()) .allow_methods([Method::GET, Method::POST, Method::PUT, Method::DELETE]) .allow_headers([AUTHORIZATION, CONTENT_TYPE]) .max_age(Duration::from_secs(3600)) ) ) } // 连接保持配置 pub fn create_server() -> Result, Box> { let addr = SocketAddr::from(([0, 0, 0, 0], 3000)); Server::bind(&addr) .http1_keepalive(true) .http1_half_close(true) .http2_keep_alive_interval(Some(Duration::from_secs(30))) .http2_keep_alive_timeout(Duration::from_secs(10)) .serve(app.into_make_service()) } ``` ## 🔒 安全加固 ### 1. 应用层安全 #### 输入验证和清理 ```rust // src/validation/security.rs use regex::Regex; use once_cell::sync::Lazy; static EMAIL_REGEX: Lazy = Lazy::new(|| { Regex::new(r"^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$").unwrap() }); static USERNAME_REGEX: Lazy = Lazy::new(|| { Regex::new(r"^[a-zA-Z0-9_]{3,20}$").unwrap() }); pub fn validate_email(email: &str) -> Result<(), ValidationError> { if email.len() > 254 { return Err(ValidationError::new("email_too_long")); } if !EMAIL_REGEX.is_match(email) { return Err(ValidationError::new("invalid_email_format")); } Ok(()) } pub fn validate_username(username: &str) -> Result<(), ValidationError> { if !USERNAME_REGEX.is_match(username) { return Err(ValidationError::new("invalid_username")); } // 检查是否包含敏感词 let forbidden_words = ["admin", "root", "system", "api"]; if forbidden_words.iter().any(|&word| username.to_lowercase().contains(word)) { return Err(ValidationError::new("forbidden_username")); } Ok(()) } // SQL注入防护 pub fn sanitize_sql_input(input: &str) -> String { input .replace("'", "''") .replace("\"", "\"\"") .replace(";", "") .replace("--", "") .replace("/*", "") .replace("*/", "") } // XSS防护 pub fn sanitize_html(input: &str) -> String { input .replace("<", "<") .replace(">", ">") .replace("\"", """) .replace("'", "'") .replace("/", "/") } ``` #### 密码安全 ```rust // src/auth/password.rs use argon2::{Argon2, PasswordHash, PasswordHasher, PasswordVerifier}; use argon2::password_hash::{rand_core::OsRng, SaltString}; use zxcvbn::zxcvbn; pub struct PasswordSecurity; impl PasswordSecurity { pub fn hash_password(password: &str) -> Result { let salt = SaltString::generate(&mut OsRng); let argon2 = Argon2::default(); let password_hash = argon2.hash_password(password.as_bytes(), &salt)?; Ok(password_hash.to_string()) } pub fn verify_password(password: &str, hash: &str) -> Result { let parsed_hash = PasswordHash::new(hash)?; let argon2 = Argon2::default(); Ok(argon2.verify_password(password.as_bytes(), &parsed_hash).is_ok()) } pub fn check_password_strength(password: &str) -> Result<(), ValidationError> { if password.len() < 8 { return Err(ValidationError::new("password_too_short")); } if password.len() > 128 { return Err(ValidationError::new("password_too_long")); } // 使用zxcvbn检查密码强度 let estimate = zxcvbn(password, &[]).unwrap(); if estimate.score() < 3 { return Err(ValidationError::new("password_too_weak")); } // 检查字符类型 let has_lower = password.chars().any(|c| c.is_lowercase()); let has_upper = password.chars().any(|c| c.is_uppercase()); let has_digit = password.chars().any(|c| c.is_numeric()); let has_special = password.chars().any(|c| "!@#$%^&*()_+-=[]{}|;:,.<>?".contains(c)); let char_types = [has_lower, has_upper, has_digit, has_special] .iter() .filter(|&&x| x) .count(); if char_types < 3 { return Err(ValidationError::new("password_insufficient_complexity")); } Ok(()) } } ``` #### JWT安全 ```rust // src/auth/jwt.rs use jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation}; use serde::{Deserialize, Serialize}; use std::time::{SystemTime, UNIX_EPOCH}; #[derive(Debug, Serialize, Deserialize)] pub struct Claims { pub sub: String, pub exp: usize, pub iat: usize, pub iss: String, pub aud: String, pub jti: String, pub role: String, } pub struct JwtSecurity { encoding_key: EncodingKey, decoding_key: DecodingKey, validation: Validation, } impl JwtSecurity { pub fn new(secret: &str) -> Self { let mut validation = Validation::new(Algorithm::HS256); validation.set_issuer(&["rust-user-api"]); validation.set_audience(&["api-users"]); validation.leeway = 60; // 1分钟时钟偏差容忍 Self { encoding_key: EncodingKey::from_secret(secret.as_ref()), decoding_key: DecodingKey::from_secret(secret.as_ref()), validation, } } pub fn create_token(&self, user_id: &str, role: &str) -> Result { let now = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as usize; let exp = now + 3600; // 1小时过期 let claims = Claims { sub: user_id.to_string(), exp, iat: now, iss: "rust-user-api".to_string(), aud: "api-users".to_string(), jti: uuid::Uuid::new_v4().to_string(), // JWT ID防重放 role: role.to_string(), }; encode(&Header::default(), &claims, &self.encoding_key) } pub fn verify_token(&self, token: &str) -> Result { let token_data = decode::(token, &self.decoding_key, &self.validation)?; Ok(token_data.claims) } } ``` ### 2. 网络层安全 #### TLS配置 ```rust // src/server/tls.rs use rustls::{Certificate, PrivateKey, ServerConfig}; use rustls_pemfile::{certs, pkcs8_private_keys}; use std::fs::File; use std::io::BufReader; pub fn load_tls_config(cert_path: &str, key_path: &str) -> Result> { let cert_file = &mut BufReader::new(File::open(cert_path)?); let key_file = &mut BufReader::new(File::open(key_path)?); let cert_chain = certs(cert_file)? .into_iter() .map(Certificate) .collect(); let mut keys: Vec = pkcs8_private_keys(key_file)? .into_iter() .map(PrivateKey) .collect(); if keys.is_empty() { return Err("No private key found".into()); } let config = ServerConfig::builder() .with_safe_default_cipher_suites() .with_safe_default_kx_groups() .with_safe_default_protocol_versions()? .with_no_client_auth() .with_single_cert(cert_chain, keys.remove(0))?; Ok(config) } ``` #### 安全头中间件 ```rust // src/middleware/security_headers.rs use axum::{ http::{header, HeaderMap, HeaderValue, Request, Response}, middleware::Next, response::IntoResponse, }; pub async fn security_headers( request: Request, next: Next, ) -> impl IntoResponse { let mut response = next.run(request).await; let headers = response.headers_mut(); // HSTS headers.insert( header::STRICT_TRANSPORT_SECURITY, HeaderValue::from_static("max-age=31536000; includeSubDomains; preload"), ); // CSP headers.insert( header::CONTENT_SECURITY_POLICY, HeaderValue::from_static("default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'"), ); // X-Frame-Options headers.insert( header::X_FRAME_OPTIONS, HeaderValue::from_static("DENY"), ); // X-Content-Type-Options headers.insert( header::X_CONTENT_TYPE_OPTIONS, HeaderValue::from_static("nosniff"), ); // X-XSS-Protection headers.insert( HeaderValue::from_static("x-xss-protection"), HeaderValue::from_static("1; mode=block"), ); // Referrer Policy headers.insert( HeaderValue::from_static("referrer-policy"), HeaderValue::from_static("strict-origin-when-cross-origin"), ); // Permissions Policy headers.insert( HeaderValue::from_static("permissions-policy"), HeaderValue::from_static("geolocation=(), microphone=(), camera=()"), ); response } ``` ### 3. 数据库安全 #### 连接安全 ```rust // src/database/security.rs use sqlx::{sqlite::SqliteConnectOptions, ConnectOptions, SqlitePool}; use std::str::FromStr; pub async fn create_secure_pool(database_url: &str) -> Result { let mut options = SqliteConnectOptions::from_str(database_url)? .create_if_missing(true) .journal_mode(sqlx::sqlite::SqliteJournalMode::Wal) .synchronous(sqlx::sqlite::SqliteSynchronous::Normal) .busy_timeout(std::time::Duration::from_secs(30)) .pragma("cache_size", "1000000") .pragma("temp_store", "memory") .pragma("mmap_size", "268435456"); // 禁用不安全的功能 options = options .pragma("trusted_schema", "OFF") .pragma("defensive", "ON"); // 设置日志级别 options.log_statements(log::LevelFilter::Debug); SqlitePool::connect_with(options).await } // 数据加密 pub fn encrypt_sensitive_data(data: &str, key: &[u8]) -> Result> { use aes_gcm::{Aes256Gcm, Key, Nonce}; use aes_gcm::aead::{Aead, NewAead}; use rand::Rng; let cipher = Aes256Gcm::new(Key::from_slice(key)); let nonce_bytes: [u8; 12] = rand::thread_rng().gen(); let nonce = Nonce::from_slice(&nonce_bytes); let ciphertext = cipher.encrypt(nonce, data.as_bytes())?; // 组合nonce和密文 let mut result = nonce_bytes.to_vec(); result.extend_from_slice(&ciphertext); Ok(base64::encode(result)) } pub fn decrypt_sensitive_data(encrypted_data: &str, key: &[u8]) -> Result> { use aes_gcm::{Aes256Gcm, Key, Nonce}; use aes_gcm::aead::{Aead, NewAead}; let data = base64::decode(encrypted_data)?; if data.len() < 12 { return Err("Invalid encrypted data".into()); } let (nonce_bytes, ciphertext) = data.split_at(12); let cipher = Aes256Gcm::new(Key::from_slice(key)); let nonce = Nonce::from_slice(nonce_bytes); let plaintext = cipher.decrypt(nonce, ciphertext)?; Ok(String::from_utf8(plaintext)?) } ``` ### 4. 监控和审计 #### 安全事件监控 ```rust // src/security/monitoring.rs use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::sync::Arc; use tokio::sync::RwLock; #[derive(Debug, Serialize, Deserialize)] pub struct SecurityEvent { pub event_type: SecurityEventType, pub timestamp: chrono::DateTime, pub source_ip: String, pub user_id: Option, pub details: HashMap, pub severity: SecuritySeverity, } #[derive(Debug, Serialize, Deserialize)] pub enum SecurityEventType { LoginAttempt, LoginFailure, BruteForceDetected, SuspiciousActivity, UnauthorizedAccess, DataBreach, SystemIntrusion, } #[derive(Debug, Serialize, Deserialize)] pub enum SecuritySeverity { Low, Medium, High, Critical, } pub struct SecurityMonitor { events: Arc>>, alert_thresholds: HashMap, } impl SecurityMonitor { pub fn new() -> Self { let mut thresholds = HashMap::new(); thresholds.insert(SecurityEventType::LoginFailure, 5); thresholds.insert(SecurityEventType::BruteForceDetected, 1); thresholds.insert(SecurityEventType::UnauthorizedAccess, 3); Self { events: Arc::new(RwLock::new(Vec::new())), alert_thresholds: thresholds, } } pub async fn log_event(&self, event: SecurityEvent) { let mut events = self.events.write().await; events.push(event.clone()); // 检查是否需要触发告警 if self.should_alert(&event).await { self.send_alert(&event).await; } // 清理旧事件(保留最近1000个) if events.len() > 1000 { events.drain(0..events.len() - 1000); } } async fn should_alert(&self, event: &SecurityEvent) -> bool { if let Some(&threshold) = self.alert_thresholds.get(&event.event_type) { let events = self.events.read().await; let recent_events = events .iter() .filter(|e| { e.event_type == event.event_type && e.source_ip == event.source_ip && e.timestamp > chrono::Utc::now() - chrono::Duration::hours(1) }) .count(); return recent_events >= threshold; } matches!(event.severity, SecuritySeverity::Critical) } async fn send_alert(&self, event: &SecurityEvent) { // 发送告警通知 log::error!("Security Alert: {:?}", event); // 这里可以集成邮件、短信、Slack等通知方式 // send_email_alert(event).await; // send_slack_alert(event).await; } } ``` ### 5. 部署安全 #### Docker安全配置 ```dockerfile # 安全的Dockerfile FROM rust:1.88-slim as builder # 创建非特权用户 RUN groupadd -r rustuser && useradd -r -g rustuser rustuser WORKDIR /app COPY . . RUN cargo build --release FROM debian:bookworm-slim # 安装安全更新 RUN apt-get update && apt-get upgrade -y && \ apt-get install -y --no-install-recommends \ ca-certificates \ sqlite3 \ libssl3 \ curl && \ rm -rf /var/lib/apt/lists/* && \ apt-get clean # 创建非特权用户 RUN groupadd -r apiuser && useradd -r -g apiuser apiuser # 创建应用目录 RUN mkdir -p /app/data /app/logs && \ chown -R apiuser:apiuser /app # 复制二进制文件 COPY --from=builder /app/target/release/rust-user-api /app/ COPY --from=builder /app/migrations /app/migrations/ # 设置权限 RUN chmod +x /app/rust-user-api && \ chown apiuser:apiuser /app/rust-user-api # 切换到非特权用户 USER apiuser # 健康检查 HEALTHCHECK --interval=30s --timeout=10s --start-period=5s --retries=3 \ CMD curl -f http://localhost:3000/health || exit 1 EXPOSE 3000 CMD ["/app/rust-user-api"] ``` #### 系统安全配置 ```bash #!/bin/bash # security-hardening.sh # 系统安全加固脚本 # 1. 更新系统 apt update && apt upgrade -y # 2. 安装安全工具 apt install -y fail2ban ufw rkhunter chkrootkit # 3. 配置防火墙 ufw default deny incoming ufw default allow outgoing ufw allow ssh ufw allow 80/tcp ufw allow 443/tcp ufw --force enable # 4. 配置fail2ban cat > /etc/fail2ban/jail.local << 'EOF' [DEFAULT] bantime = 3600 findtime = 600 maxretry = 5 [sshd] enabled = true port = ssh logpath = /var/log/auth.log maxret