本文档介绍 Backtrader Web 的安全最佳实践。
- 最小长度: 8 个字符
- 必须包含: 大写字母、小写字母、数字、特殊字符
- 使用 bcrypt 加密存储 (cost=12)
- Access Token 有效期: 24 小时
- Refresh Token 有效期: 30 天
- Refresh Token 轮换机制
- 使用 SHA-256 哈希存储 Refresh Token
# 生成安全密钥
python -c "import secrets; print(secrets.token_urlsafe(32))"
# 在生产环境中设置
SECRET_KEY=<生成的密钥>
JWT_SECRET_KEY=<另一个生成的密钥>使用参数化查询,避免字符串拼接:
# ✅ 正确
await session.execute(
select(User).where(User.id == user_id)
)
# ❌ 错误
await session.execute(
f"SELECT * FROM users WHERE id = '{user_id}'"
)- 所有用户输入都需要经过验证和清理
- 使用 Content-Security-Policy 头
- 对输出进行 HTML 转义
# ✅ 正确 - 使用参数验证
from app.utils.validation import detect_command_injection
if detect_command_injection(user_input):
raise InvalidInputError("Invalid input")
# ❌ 错误 - 直接使用用户输入
os.system(f"process_data {user_input}")- 认证接口: 10 次/分钟
- 其他接口: 60 次/分钟
- 超过限制返回 429 状态码
# 生产环境 CORS 配置
CORS_ORIGINS=https://yourdomain.com,https://app.yourdomain.com生产环境必须使用 HTTPS:
# 强制 HTTPS
SECURE_SSL_REDIRECT=true
SESSION_COOKIE_SECURE=true
CSRF_COOKIE_SECURE=true- 密码: bcrypt 加密
- API 密钥: 加密存储
- 数据库: 使用 SSL 连接
- 定期备份数据库
- 异地存储备份
- 测试恢复流程
- 不记录敏感信息 (密码、Token)
- 日志文件权限控制
- 定期清理旧日志
- 用户只能访问自己的数据
- 管理员可以访问所有数据
- 使用 RBAC (基于角色的访问控制)
# 检查资源所有权
if task.user_id != current_user.id and not current_user.is_admin:
raise InsufficientPermissionsError(resource="backtest_task")- 修改默认 SECRET_KEY
- 修改默认 JWT_SECRET_KEY
- 修改默认管理员密码
- 配置 CORS_ORIGINS
- 启用 HTTPS
- 配置速率限制
- 关闭 DEBUG 模式
# 必须修改
SECRET_KEY=change-me-in-production
JWT_SECRET_KEY=change-me-in-production
ADMIN_PASSWORD=change-me-in-production
# 生产环境
DEBUG=false
DATABASE_URL=postgresql+asyncpg://user:pass@host/db监控以下安全事件:
- 登录失败
- 速率限制触发
- 异常请求
- SQL 注入尝试
配置关键安全事件的告警:
from app.utils.logger import audit_logger
# 登录失败告警
audit_logger.log_login(username, success=False, ip=client_ip)- 检查 SQL 查询
- 检查用户输入处理
- 检查权限验证
# 检查过期的依赖
pip list --outdated
# 更新依赖
pip install --upgrade package_name# 安全扫描
pip install safety
safety check
# 代码扫描
pip install bandit
bandit -r app/问题: 使用默认的密钥和密码
解决: 部署前必须修改所有默认值
问题: 生产环境开启 DEBUG
解决: 设置 DEBUG=false
问题: 错误信息暴露敏感数据
解决: 使用统一错误处理
问题: 直接反序列化用户输入
解决: 使用 Pydantic 验证所有输入