Files
FinDataHub/security-audit-report.md
FinDataHub d7d2a1e8ad chore(repo): 补齐长期未入库的核心源码、文档与本次复查修复
背景
- 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 已部署
2026-09-18 22:37:55 +08:00

5.3 KiB
Raw Permalink Blame History

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 防护。

代码路径

  1. 入口: content_enricher.py:240 - enrich_item() 函数接收新闻数据
  2. URL 获取: url = item.get("url") - 从新闻项中提取 URL
  3. 安全校验: content_enricher.py:181 - _is_safe_url(url) 仅校验初始 URL
  4. 请求发送: content_enricher.py:190 - httpx.AsyncClient(timeout=timeout, follow_redirects=True) - 配置跟随重定向
  5. 重定向绕过: 外部服务器返回 Location: http://169.254.169.254/latest/meta-data/
  6. 影响: 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 暴露。


安全良好实践

代码库中已实现多项安全防护措施,值得肯定:

  1. SQL 注入防护: 所有表名均通过白名单校验(_check_table()),数据查询使用参数化语句
  2. 密码安全: 使用 secrets.compare_digest() 防止时序攻击,API Key 使用 secrets.token_urlsafe() 生成
  3. XSS 防护: 前端 v-html 输出前进行 HTML 转义(NewsCard.vue:113)
  4. 敏感数据加密: macOS App 使用 AES-256-GCM 加密存储密钥,密钥派生自机器标识
  5. 速率限制: 搜索接口实现了基于 IP 的令牌桶限流
  6. 安全头: FastAPI 应用配置了 X-Content-Type-Options、X-Frame-Options 等安全响应头
  7. 文件权限: API Key 文件权限设置为 0o600

结论

审计完成 — 发现 1 个中等严重度已确认漏洞(SSRF 重定向绕过)。

建议优先修复 SSRF 重定向绕过漏洞,特别是当服务部署在云环境中时,该漏洞可能导致云凭证泄露。