FinBuddy 安全修复与分层重构
· FinBuddy
今日进展
- 修复 P0 安全风险:SQL 注入防护、LLM 生成 SQL 安全校验、裸 except 吞异常修复(23 处)
- 修复 P1 分层违规:从 routes 层抽取业务逻辑到 services,routes 只做参数校验和调度
- 中间件增强:新增 execute_raw_query()、get_market_db_path()、get_all_custom_experts() 等方法
关键代码/伪代码
SQL 注入防护 — 白名单校验
# market_db.py: 新增 _validate_identifier 白名单校验
# 只允许字母、数字、下划线,防止 SQL 注入
# 背景:LLM 可能生成包含特殊字符的表名/列名,
# 如果直接拼接到 SQL 中,就有注入风险
FUNCTION _validate_identifier(name: str) -> str:
# 正则:必须以字母或下划线开头,后跟字母/数字/下划线
# 拒绝:空格、分号、引号、注释符等 SQL 注入字符
IF NOT re.match(r'^[a-zA-Z_][a-zA-Z0-9_]*$', name):
RAISE ValueError(f"非法标识符: {name}")
RETURN name
# 使用:所有动态表名/列名必须经过校验
# 修复前(危险):query = f"SELECT * FROM {table_name}"
# 修复后(安全):
query = f"SELECT * FROM {_validate_identifier(table_name)}"
分层重构 — routes 提取到 services
# 重构前: routes/simulation.py 包含 510+ 行业务逻辑
# 问题:routes 层既做参数校验又做业务逻辑,职责不清
# 重构后: 业务逻辑抽取到 services/simulation/simulation_service.py
# routes/simulation.py (重构后 — 只做参数校验和调度)
@router.post("/simulation/run")
ASYNC def run_simulation(request: SimulationRequest):
validated = validate_request(request) # 参数校验
result = await simulation_service.run(validated) # 委托 service
RETURN ApiResponse(data=result)
# services/simulation/simulation_service.py (新增 — 业务逻辑)
CLASS SimulationService:
ASYNC DEF run(self, params) -> SimulationResult:
# Step1: 构建回测场景(股票、时间范围、初始资金)
scenario = self._build_scenario(params)
# Step2: 创建 Backtrader 引擎并执行
engine = BacktraderEngine(scenario)
result = await engine.run()
# Step3: 格式化结果(必须包含回测免责声明)
RETURN self._format_result(result)
中间件统一访问
# 重构前: 各模块直接 import db 路径和实例
# 问题:硬编码路径散落各处,改数据库位置要改 N 个文件
# 重构后: 统一通过中间件访问,改一处全站生效
# data_manager.py 改为:
# 修复前: db_path = "/hardcoded/path/to/finbuddy_market.db"
# 修复后:
db_path = get_middleware().get_market_db_path()
# market.py 改为:
# 修复前: middleware = MarketMiddleware(db_path) # 每次新建实例
# 修复后:
middleware = get_middleware() # 单例,全局唯一
# llm_parser.py 改为:
# 修复前: experts = 直接查数据库获取专家列表
# 修复后:
experts = get_middleware().get_all_custom_experts()
遇到的问题
- SVN 服务器上 SVN 1.7.14 版本太老,中文 commit message 显示乱码(GBK 编码问题),需要本地转码才能看到完整提交说明
- 23 处裸 except 分布在 8 个文件中,逐个排查耗时较长,最后用 grep 批量定位
- simulation_service 从 routes 抽取时,依赖关系较复杂(引用了 4 个 middleware 方法),需要确保中间件方法先就位
明日计划
- 继续 services 目录按业务域拆分:agent/backtest/knowledge/market/report/system/watchlist
- middleware 目录按业务域拆分:business/market/news/tdx/watch
- 新增合规违规文件清单文档