V2 安全升级计划
分支:
v2-security-upgrade| 目标: 平衡开发便捷性与生产安全性
执行原则
环境分级策略
| 环境 | 安全级别 | 便捷性 | 特点 |
|---|---|---|---|
development | 低 | 高 | 允许 auth_disabled, 宽松 CORS |
staging | 中 | 中 | 强制认证, 允许测试域名 CORS |
production | 高 | 低 | 严格 CORS, 私钥加密, 完整审计 |
核心设计
┌─────────────────────────────────────────────────────────────────┐
│ 环境感知安全配置 │
│ if environment == "development" → 便捷模式 │
│ if environment == "staging" → 平衡模式 │
│ if environment == "production" → 安全模式 │
└─────────────────────────────────────────────────────────────────┘
Phase 1: 安全基础设施 (P0)
1.1 CORS 环境感知配置
fn create_cors_layer(config: &AppConfig) -> CorsLayer {
match config.environment.as_str() {
"development" => {
// 开发环境: 允许所有来源
CorsLayer::new()
.allow_origin(Any)
.allow_methods(Any)
.allow_headers(Any)
}
"staging" => {
// 测试环境: 允许测试域名
CorsLayer::new()
.allow_origin([
"https://8a27.xyz".parse().unwrap(),
"http://localhost:3000".parse().unwrap(),
])
.allow_credentials(true)
}
_ => {
// 生产环境: 仅允许正式域名
CorsLayer::new()
.allow_origin([
"https://renance.xyz".parse().unwrap(),
"https://app.renance.xyz".parse().unwrap(),
])
.allow_credentials(true)
}
}
}
1.2 认证绕过环境保护
if state.config.is_auth_disabled() {
// 安全检查: 仅 development 环境允许禁用认证
if state.config.environment != "development" {
tracing::error!(
"SECURITY: AUTH_DISABLED=true in {} environment! Ignoring.",
state.config.environment
);
// 不绕过认证,继续正常验证流程
} else {
tracing::warn!("Auth disabled in development mode");
// 允许绕过
}
}
1.3 认证错误信息脱敏
- 开发环境: 显示详细错误信息
- 生产环境: 返回统一的 "Authentication failed"
Phase 2: 数据完整性 (P1)
2.1 数据库事务支持
pub async fn persist_trade(pool: &PgPool, trade: &TradeEvent) -> Result<(), MatchingError> {
let mut tx = pool.begin().await?;
// 1. 插入交易记录
sqlx::query("INSERT INTO trades ...").execute(&mut *tx).await?;
// 2. 更新 Maker 仓位
Self::update_position(&mut tx, &trade.maker).await?;
// 3. 更新 Taker 仓位
Self::update_position(&mut tx, &trade.taker).await?;
// 4. 提交事务
tx.commit().await?;
Ok(())
}
2.2 重试机制
pub struct RetryConfig {
pub max_attempts: u32, // 默认 3
pub initial_delay_ms: u64, // 默认 100ms
pub max_delay_ms: u64, // 默认 5000ms
pub backoff_multiplier: f64, // 默认 2.0
}
2.3 死信队列
失败超过重试次数的交易写入 dead_letter_trades 表,便于后续人工处理。
Phase 3: 性能优化 (P1)
3.1 修复 N+1 查询
优化前: 每个仓位单独查询价格 优化后: 批量获取所有需要的价格
// 批量获取所有需要的价格 (一次查询)
let symbols: Vec<String> = positions.iter().map(|p| p.symbol.clone()).collect();
let prices = state.price_feed_service
.batch_get_mark_prices(&symbols)
.await
.unwrap_or_default();
Phase 4: 常量提取 (P2)
全局常量模块
// backend/src/constants.rs
/// 缓存 TTL (秒)
pub mod cache_ttl {
pub const PRICE: u64 = 5;
pub const TICKER: u64 = 5;
pub const BALANCE: u64 = 30;
pub const POSITIONS: u64 = 10;
pub const SESSION: u64 = 86400; // 24 hours
}
/// USDT 精度
pub mod precision {
pub const USDT_DECIMALS: u8 = 6;
pub const USDT_MULTIPLIER: u64 = 1_000_000;
}
/// 通道容量
pub mod channels {
pub const TRADE_CHANNEL_CAPACITY: usize = 10000;
pub const ORDERBOOK_CHANNEL_CAPACITY: usize = 10000;
}
Phase 5: 启动验证 (P2)
配置验证器
impl ConfigValidator {
pub fn validate(config: &AppConfig) -> Result<()> {
let mut errors = Vec::new();
// 必填项检查
if config.jwt_secret.len() < 32 {
errors.push("JWT_SECRET must be at least 32 characters");
}
// 生产环境特殊检查
if config.environment == "production" {
if config.auth_disabled {
errors.push("AUTH_DISABLED cannot be true in production");
}
// 检查是否使用了 Hardhat 测试私钥
if config.backend_signer_private_key.contains("ac0974bec") {
errors.push("Production cannot use Hardhat test private key!");
}
}
if !errors.is_empty() {
bail!("Configuration errors:\n - {}", errors.join("\n - "));
}
Ok(())
}
}
执行时间线
| 周次 | 阶段 | 内容 |
|---|---|---|
| Week 1 | Phase 1 | CORS 环境感知、认证保护、错误脱敏 |
| Week 2 | Phase 2 | 数据库事务、重试机制、死信队列 |
| Week 3 | Phase 3-4 | N+1 查询修复、常量模块 |
| Week 4 | Phase 5-6 | 配置验证、main.rs 拆分 |
测试策略
本地测试
# 开发环境
ENVIRONMENT=development AUTH_DISABLED=true cargo run
# 模拟生产环境
ENVIRONMENT=production AUTH_DISABLED=false cargo run
# 应该: 拒绝启动如果有配置问题
测试服务器 (8a27.xyz)
ENVIRONMENT=staging
CORS_ALLOWED_ORIGINS=https://8a27.xyz,http://localhost:3000
生产环境 (renance.xyz)
ENVIRONMENT=production
CORS_ALLOWED_ORIGINS=https://renance.xyz
# AUTH_DISABLED 无效,强制认证
回滚计划
如果出现问题:
git checkout dev回到稳定分支- 重新部署 dev 分支代码
- 分析问题后在 v2 分支修复