背景
- HEAD 长期停在 08-03 的安全审计提交,此后六周的工作全部只在工作区。
- 更严重的是部分源码从未进入过版本控制(非"改了没提交"):
· Services/findatahub-core/ 索引 0 条 —— 18 个核心模块(pipeline/gate/cleaner/
db/cross_validator/health/retry…)全新 clone 拿不到
· Services/findatahub-client/ 索引 0 条
· App/Sources 磁盘 74 个 .swift、索引 54 —— 20 个未入库(AutoRecoveryManager、
全套 Settings*Section、PowerSaver、MySQLOnDemandManager、DependencyScanner…)
一次 `git clean -fd`、误删目录或磁盘故障即可不可恢复地丢失这些文件。
本提交内容
1. 补齐上述未跟踪源码、测试、文档与报告(Services/App/Docs/Tests/根报告)。
2. 纳入 .workbuddy/memory(项目知识)与 .github CI 配置。
3. 本次代码与架构复查的修复(详见下一段说明):
- Scripts/bin/common.py PidManager.status 改 split(":", 1),修复时间戳被截断到整点
- Scripts/bin/db_pool.py 取连接加超时、归还前 rollback、失败归还池位、双检锁初始化
- Scripts/bin/newsflash_backend.py _query_all 改 try/finally 无条件归还连接
- Scripts/bin/newsflash_collect.py 新增 _install_crash_handlers(faulthandler + excepthook)
- tushare_fetcher/core/fetcher.py _fetch_static 增量走 upsert,仅全量快照才 replace
- tushare_fetcher/scripts/tushare_sync.sh 银层迁移补 stock_weekly/stock_monthly;
月度增加分红按报告期全量刷新
- kuaixun-service/extend/content_enricher.py 禁用自动重定向 + 逐跳 SSRF 校验
- App/.../AutoRecoveryManager.swift 反复故障改告警不熔断(避免拉长数据空窗)
- 新增 Scripts/bin/repair_dividend_history.py(分红历史修复,按报告期分页幂等 upsert)
- 新增 Docs/repro/*(两个可运行的缺陷复现脚本)
- 补齐 6 个文件共 20 条回归用例(均做过证伪:旧实现下必然失败)
安全
- 已确认未纳入任何凭据:Services/tushare_fetcher/.env 被其 .gitignore 覆盖;
~/.config/findatahub/env(0600)在仓库外。
验证
- Python 测试 1074 passed(Scripts/bin 207 / core 105 / tushare 174 / kuaixun 405 / akshare 183)
- Swift 经 `swift build --disable-sandbox` 编译通过,产物 v1.5.2 已部署
5.3 KiB
FinDataHub 安全审计报告
审计日期: 2026-08-30
审计范围: 全代码库(macOS App、快讯服务、数据客户端、采集服务等)
审计目标: 识别中等严重度及以上的已确认漏洞,具备可论证的端到端利用路径
审计摘要
本次审计对 FinDataHub 代码库进行了系统性安全评估,覆盖以下攻击面:
- 认证与访问控制
- SQL 注入与命令注入
- 跨站脚本(XSS)
- 服务端请求伪造(SSRF)
- 敏感数据处理
- 外部交互与第三方集成
发现 1 个中等严重度漏洞,其余问题均为低风险或已正确防护。
中等严重度漏洞
漏洞 1: SSRF 重定向绕过
严重度: 中等
位置: Services/kuaixun-service/extend/content_enricher.py
攻击者画像: 能够控制新闻数据源的外部攻击者(如被采集网站的所有者),或拥有内部 API Key 的已认证用户
漏洞描述
内容增强模块的 fetch_article_text() 函数在抓取新闻原文时,对 URL 进行了 SSRF 防护校验(_is_safe_url()),但该校验仅在请求前检查初始 URL,而 httpx 客户端配置了 follow_redirects=True,会自动跟随 HTTP 重定向。
攻击者可以构造一个指向外部服务器的 URL,该服务器返回 302 重定向到内网地址(如 127.0.0.1、169.254.169.254 等),从而绕过 SSRF 防护。
代码路径
- 入口:
content_enricher.py:240-enrich_item()函数接收新闻数据 - URL 获取:
url = item.get("url")- 从新闻项中提取 URL - 安全校验:
content_enricher.py:181-_is_safe_url(url)仅校验初始 URL - 请求发送:
content_enricher.py:190-httpx.AsyncClient(timeout=timeout, follow_redirects=True)- 配置跟随重定向 - 重定向绕过: 外部服务器返回
Location: http://169.254.169.254/latest/meta-data/ - 影响: httpx 自动请求内网地址,响应内容被截断为 2000 字符后返回
可控输入向量
- 新闻项的
url字段(通过采集器从外部网站获取,或通过内部 API/api/v1/news/batch写入)
影响
- 内网服务探测: 可探测内网开放端口和服务
- 云元数据泄露: 如果部署在云环境中,可能访问云服务元数据端点(如 AWS IMDS)
- 敏感信息读取: 可能读取内网 HTTP 服务的响应内容(最多 2000 字符)
修复建议
方案 A(推荐): 重定向后再次校验
# 禁用自动重定向,手动处理并每次校验
async with httpx.AsyncClient(timeout=timeout, follow_redirects=False) as client:
current_url = url
for _ in range(5): # 最多5次重定向
if not _is_safe_url(current_url):
logger.debug(f"重定向目标不安全: {current_url}")
return ""
resp = await client.get(current_url, headers=headers)
if resp.status_code in (301, 302, 303, 307, 308):
current_url = resp.headers.get("Location", "")
continue
if resp.status_code >= 400:
return ""
html = resp.text
break
方案 B: 使用 transport 级别的地址校验
使用 httpx 的 transport 钩子,在建立连接前对所有目标地址进行校验。
低风险发现(不构成中等严重度威胁)
以下问题已确认存在,但严重度较低,不满足本次审计的中等及以上报告标准:
1. CORS 配置过于宽松
位置: Services/findatahub-client/src/findatahub/api.py:35-40
allow_origins=["*"] 允许所有来源的跨域请求。由于该 API 无认证机制且所有数据均为公开金融数据,实际影响有限。
2. 收藏接口无认证
位置: Services/kuaixun-service/app/routers/public.py:103-113
用户身份完全由 X-User-ID 请求头控制,无需认证。但系统设计为单用户模式,且收藏数据敏感度较低。
3. kuaixun-service 缺少 CORS 中间件
位置: Services/kuaixun-service/app/main.py
虽然定义了 CORS_ORIGINS 变量,但未实际配置 CORSMiddleware。前端通过同域或反向代理访问,不影响功能。
4. archive_data.py 表名 SQL 拼接
位置: Scripts/bin/archive_data.py
--table 参数直接拼接到 SQL 语句中。但该脚本为本地命令行工具,不通过 Web 暴露。
安全良好实践
代码库中已实现多项安全防护措施,值得肯定:
- SQL 注入防护: 所有表名均通过白名单校验(
_check_table()),数据查询使用参数化语句 - 密码安全: 使用
secrets.compare_digest()防止时序攻击,API Key 使用secrets.token_urlsafe()生成 - XSS 防护: 前端
v-html输出前进行 HTML 转义(NewsCard.vue:113) - 敏感数据加密: macOS App 使用 AES-256-GCM 加密存储密钥,密钥派生自机器标识
- 速率限制: 搜索接口实现了基于 IP 的令牌桶限流
- 安全头: FastAPI 应用配置了 X-Content-Type-Options、X-Frame-Options 等安全响应头
- 文件权限: API Key 文件权限设置为
0o600
结论
审计完成 — 发现 1 个中等严重度已确认漏洞(SSRF 重定向绕过)。
建议优先修复 SSRF 重定向绕过漏洞,特别是当服务部署在云环境中时,该漏洞可能导致云凭证泄露。