Files
ephron-ren-prd/2026-05-16-ephron-security-audit-prd.md

8.8 KiB
Raw Blame History

ephron.ren 安全审计总 PRD2026-05-16 汇总版)

文档目的

本 PRD 汇总 2026-05-16 对 ephron.ren 进行的多轮安全审计结果,统一记录:

  • 已确认安全基线
  • 已确认漏洞 / 缺陷
  • 已排除或降级的候选问题
  • 配置风险与后续修复优先级

本文件用于替代分散的 round2 / round3 阶段记录,作为当前单一汇总版本。


一、审计范围

本轮覆盖以下服务与共享模块:

  • auth
  • blog
  • canvas
  • home
  • prompt
  • shared

审计方式:

  • 全仓静态源码审计
  • 非破坏性线上动态验证
  • 仅进行低风险、只读或受控请求验证

二、总体结论

当前总体判断

ephron.ren 不是裸奔状态,具备较明确的基础安全基线:

  • 服务端 admin 鉴权存在
  • 权限检查存在
  • 统一安全响应头在线上已生效
  • 大部分 admin 写操作具备 CSRF 防护
  • service token 与 admin 边界总体存在
  • blog 图片上传链具备权限、CSRF、大小限制和重编码处理
  • auth 登录跳转链具备 redirect 校验

但本次审计也确认了数个真实问题,主要集中在:

  • prompt
  • home admin

当前最准确结论仍然是:

项目具备安全基线,但不能认定为“已经安全完成”;已确认若干需尽快修复的问题。


三、已确认安全基线

1. 路由守卫结论

  • 未发现前端 SPA 式客户端路由守卫
    • 未发现 router.beforeEachcreateRouterreact-routermiddleware.ts 等典型模式
  • 存在服务端 admin 路由级鉴权/重定向
    • 各服务 admin 入口会读取 ephron_auth Cookie
    • 校验登录态与权限
    • 未登录时重定向到 auth.ephron.ren/login

2. 统一安全头在线上已确认生效

线上已确认以下响应头存在:

  • Content-Security-Policy
  • X-Frame-Options
  • X-Content-Type-Options: nosniff
  • Referrer-Policy: strict-origin-when-cross-origin

典型 CSP 现状包含:

  • frame-ancestors 'none'
  • base-uri 'self'
  • form-action 'self' https://*.ephron.ren

3. CSRF 基线存在

shared/csrf.py 已实现双提交 cookie 风格 CSRF

  • GET 生成 token
  • 表单与 Cookie 同时携带 token
  • POST 校验一致性
  • token 有时效限制
  • 使用安全比较

4. service token / admin 权限边界存在

例如 home admin 已明确拒绝 service token

  • 返回 403
  • 错误信息:Service tokens cannot access home admin

5. blog Markdown 正文链存在白名单净化

blog/src/utils/markdown.py 中:

  • Markdown 渲染后经过 bleach.clean(...)
  • 属于白名单净化,而不是裸渲染 HTML

6. blog 图片上传链具备基础防护

当前已确认:

  • 登录权限检查
  • blog.asset.upload 权限控制
  • CSRF 校验
  • 文件大小限制
  • Pillow 解码后重编码为 WebP
  • 写入固定上传目录

四、已确认问题

1. 高危:prompt /api/test-connection 匿名 SSRF / 外连探测面

结论

高危,已确认。

源码证据

prompt/src/routes/api.py

  • 存在公开 POST /api/test-connection
  • 直接接受:
    • provider
    • base_url
    • api_key
    • model
  • 服务端直接对 {payload.base_url}/chat/completions 发请求
  • 未见登录校验、权限校验、CSRF 限制

线上验证

已非破坏性验证:

  • POST https://prompt.ephron.ren/api/test-connection
  • 使用 base_url=http://127.0.0.1:9
  • 返回:200
  • 响应:{"success":false,"error":"All connection attempts failed"}

这表明:

  • 接口匿名可访问
  • 服务端确实尝试连接指定地址
  • 可被用于网络探测 / SSRF 探针

影响

  • 探测内网 / 本机 / 特定外部地址
  • 回显网络结果差异
  • 若未来可访问内部控制面或 metadata 地址,风险进一步升级

建议

  1. 该接口至少改为管理员鉴权
  2. base_url 做严格白名单
  3. 禁止 localhost / 内网 / link-local / metadata 地址
  4. 禁止透传详细网络错误
  5. 增强审计日志与限流

2. 中危:prompt 调试测试链潜在 HTML 注入 / XSS

结论

中危,已确认存在危险链路。

源码证据

prompt/static/js/test-prompt.js

  • 错误事件:
    • contentDiv.innerHTML = <div class="error">${event.detail}</div>
  • 普通异常:
    • contentDiv.innerHTML = <div class="error">${error.message}</div>
  • 流式内容:
    • contentDiv.innerHTML = this.renderMarkdown(fullContent)
    • renderMarkdown() 调用 marked.parse(text)

prompt/src/services/llm.py / prompt/src/routes/api.py

  • 上游错误文本 / 响应文本可进入错误回显链

影响

  • 管理员面自触发 / 调试型 XSS
  • 若错误页或上游响应可控,可能进一步形成可利用注入
  • 结合 CSP 中保留 'unsafe-inline',利用门槛下降

建议

  1. 错误展示改用 textContent
  2. markdown 输出增加 sanitize
  3. 后端不要透传原始 response.text
  4. 仅允许可信渲染链处理富文本

3. 中危:prompt 登录态写接口缺 CSRF

结论

中危,静态确认。

源码证据

prompt/src/routes/api.py 中以下接口依赖登录态,但未见 verify_csrf_token(...)

  • /api/prompts/{key}/test
  • /api/prompts/{key}/test/save-example

其中:

  • /test 是调试触发接口
  • /test/save-example 是明确的状态变更接口

线上验证

匿名访问会被 401 拦截,说明依赖 cookie 登录态。当前未使用真实登录态做利用验证,因此认定为静态确认缺陷

影响

  • 登录用户可能被跨站诱导发起请求
  • /test/save-example 可被用于跨站状态变更

建议

  1. 给所有 cookie 登录态写接口统一补 CSRF
  2. 抽成共用依赖,避免再漏
  3. 补自动化测试

4. 中危:home admin 编辑器存在存储型 / 自触发型 DOM XSS

结论

中危,已确认。

服务端证据

home/src/routes/admin.py

  • 把数据库内容 json.dumps(content, ensure_ascii=False) 注入模板变量 content_json

home/src/services/content.py

  • save_draft(content, uid) / publish_content(content, uid)
  • 将内容 JSON 原样入库
  • 未做字段级 HTML 清洗

前端证据

home/templates/admin/index.html

  • const initialContent = JSON.parse({{ content_json | tojson }});
  • 之后多处:
    • list.innerHTML += ... value="${exp.title}" ...
    • value="${proj.title}"
    • textarea ...>${proj.bullets.join('\n')}</textarea>
    • value="${skill.category}"
  • 即数据库内容进入 HTML 片段和属性值拼接
  • 未见可靠转义层

影响

  • 管理员打开编辑页即可触发 DOM XSS
  • 可劫持后台操作上下文
  • 可成为管理员面存储型 XSS

建议

  1. 禁止不可信数据进入 innerHTML +=
  2. 改为 createElement / .value / .textContent
  3. 为含引号 / 闭合标签 / 事件属性 payload 补回归测试

五、已复核但不应误报的点

1. 开放重定向未确认成立

auth 登录跳转链调用了 validate_redirect(),因此本轮未确认 auth 存在开放重定向漏洞

2. canvas /raw/{slug} 当前不作为确认漏洞

源码显示:

  • X-Frame-Options: SAMEORIGIN
  • raw 专用 CSPframe-ancestors 'self'
  • 用于受限 iframe 预览

当前证据不足以确认实际越界利用。

3. blog 正文链当前不报直接存储型 XSS

因为存在 bleach.clean(...) 白名单净化。

4. blog 图片上传当前未见明显任意文件上传

当前证据支持其具备基础处理链保护。


六、配置风险与需持续关注项

1. 多服务默认 development 行为是配置陷阱

多服务存在:

  • IS_DEVELOPMENT = os.getenv("ENVIRONMENT", "development") == "development"
  • docs_url="/docs" if IS_DEVELOPMENT else None
  • error_message = str(exc) if IS_DEVELOPMENT else None

这意味着:

  • 若部署漏设 ENVIRONMENT
  • 服务会默认按 development 行为运行
  • 可能意外暴露 /docs
  • 可能在 500 页面回显错误细节

判断

这是高优先级配置风险,但当前不是已确认线上漏洞。

建议

  1. 默认值改为 production
  2. 显式校验环境变量枚举值
  3. 启动时拒绝未声明环境的生产部署

七、优先级排序

P0

  1. 下线或严格鉴权 prompt /api/test-connection
  2. 修复 home admininnerHTML += 注入链

P1

  1. 修复 prompt 调试链 XSS
  2. prompt 登录态写接口补 CSRF

P2

  1. 将多服务 ENVIRONMENT 默认值改为 production
  2. 补自动化回归测试

八、最终结论

如果只问“这个项目有没有安全基线”,答案是:
如果问“这个项目现在能不能直接认定为安全”,答案是:不能

本次审计完成后,更准确的说法是:

ephron.ren 已具备基础安全防护,但仍存在若干已确认真实问题,尤其集中在 prompthome admin,需要进入修复与回归验证阶段。