zh CN 安全策略 - chiba233/yumeDSL GitHub Wiki
安全策略
受支持的版本
| 版本 | 是否支持 |
|---|---|
| 1.x | 是 |
| 0.x | 否(开发阶段) |
更详细的安全注意事项与安全 UGC 教程请参考:Security Wiki 与 Safe UGC Chat 教程。
报告漏洞
请不要为安全漏洞创建公开 Issue。
请通过私密渠道上报:
- GitHub 私密漏洞报告:访问 Security 页面并点击“Report a vulnerability”。
- 邮件:向仓库维护者发送详细信息(见 GitHub 主页联系方式)。
报告内容
报告安全问题时,请提供:
- 漏洞描述
- 复现步骤
- 受影响版本
- 影响评估(如已知)
预期流程
- 收到报告后 48 小时内确认
- 7 天内给出状态更新
- 对已确认漏洞提供修复或缓解计划
范围
本策略覆盖 yume-dsl-rich-text。以下情况不在覆盖范围:
- 你在解析器之上构建的渲染层漏洞(属于你的应用代码)
- 纯性能回退或资源放大,但仍落在已记录的 fallback / budget / coarse diff 语义内的情况
- 超大输入、超大单次编辑、或高重复对抗性输入导致的拒绝服务风险(请在应用层设置
depthLimit、输入大小限制、编辑大小限制与请求级超时)
已知安全注意事项
1. 渲染层仍然是主要信任边界
- URL 不会被自动验证:如果你把
link渲染成<a>,必须在渲染层净化url raw内容会原样透传:如果你把它渲染成 HTML,必须自行转义 / 消毒- 换句话说:解析成功不等于内容安全。
yume-dsl-rich-text负责结构正确性,不负责 HTML / URL 安全策略
2. handlers / syntax / tagName 属于受信任配置,不是用户输入面
这个库允许调用方提供:
handlerssyntaxtagNamecreateIdtracker
这些能力是为了宿主应用自定义解析行为,不是为了让终端用户动态提供解析代码或解析规则。
从实现上看:
handlers里的函数会直接在解析 / 渲染流程里执行createId会参与 parse lifecyclesyntax/tagName会直接影响扫描和识别路径tracker/baseOffset会直接影响位置结果
因此,不要把这些对象暴露为不受信任输入,也不要在 session 生命周期中原地修改它们。安全模型默认它们是应用内部的受信任配置。
3. depthLimit 只是第一层资源护栏,不是完整 DoS 防线
源码里 depthLimit 默认值是 50。它主要防的是异常深嵌套路径,不代表:
- 文档总大小已经受控
- 单次编辑成本已经受控
- diff 成本已经受控
如果输入不受信任,除了 depthLimit 之外,你仍然需要限制总文档大小、单次编辑大小与请求级执行时间。
4. 需要按 heap / CPU 预算理解风险,而不只是按输入字节数理解
这个库的结构化解析、position 跟踪、增量文档、zone、signature 与 diff 数据,都会引入明显高于原始源码大小的内存占用。
也就是说,真正需要约束的不是只有“输入几 KB / 几 MB”,还包括:
- 解析后 AST / token 树的体积
- position 数据
- 增量 session 持有的前一代 / 当前代快照
- diff 结果里的
ops/patches/dirtySpan
对于不受信任输入场景,请把heap 预算和并发解析数视为一等约束,而不是只限制请求体大小。
5. 增量 session 的设计目标是“正确新快照优先”,不是“恒定低成本”
createIncrementalSession(...) 的首要目标是推进到正确的新文档快照。为此它允许并公开以下行为:
mode可能是incremental,也可能是full-fallbackfallbackReason可能是业务内预期值,例如INTERNAL_FULL_REBUILD、AUTO_LARGE_EDIT、AUTO_COOLDOWNauto策略会根据近期样本自动偏向 full rebuild,而不是承诺始终走增量路径
默认自适应参数也说明了它是运行时策略,不是安全边界:
sampleWindowSize = 24minSamplesForAdaptation = 6maxFallbackRate = 0.35switchToFullMultiplier = 1.1fullPreferenceCooldownEdits = 12maxEditRatioForIncremental = 0.2softZoneNodeCap = 64
这些值的含义是“当增量不划算时尽快退回更稳的 full rebuild”,而不是“任何输入都保持便宜”。
6. applyEditWithDiff(...) 的 budgets 保证的是“有界退化”,不是“细粒度稳定输出”
当前 diff refinement 的默认预算是:
refinementDepthCap = 64maxComparedNodes = 20000maxAnchorCandidates = 128maxOps = 512maxSubtreeNodes = 256maxMilliseconds = 8
这些预算的作用是:一旦细粒度 diff 不划算,就尽快退化。退化后的语义是允许变粗的,而不是继续承诺“小脏区、细粒度 patch、低延迟”。
从源码行为看,以下情况都属于设计内行为,而不是安全漏洞本身:
- 返回 root-level
splice patches退化成一次replaceunchangedRanges为空dirtySpanOld/dirtySpanNew扩大到接近整篇文档- refinement 抛错后退回 conservative diff
因此,调用方不能把 applyEditWithDiff(...) 当成以下任一保证:
- 永远是细粒度 diff
- 永远只覆盖编辑窗口附近
- 永远比 full rebuild 便宜
- 永远适合直接暴露给不受信任流量
7. 高重复 raw / block 与深层 inline 仍然是资源压力热点
当前实现已经有 fallback、budget 与 coarse diff 机制,但高重复 raw / block、深层 inline、以及对锚点不友好的编辑模式,仍可能明显放大:
- CPU 比较成本
- dirty span
- diff 退化频率
- full-fallback 触发率
这类行为应该被理解为需要在部署层约束和监控的资源风险,而不是单靠解析器内部策略兜底。
8. 面向不受信任输入的最低部署要求
如果你把本库用于 UGC、协作编辑、聊天消息、富文本草稿或其他不受信任输入场景,至少应同时做到:
- 限制文档总大小
- 限制单次编辑大小 / 编辑比例
- 为请求、任务或 worker 设置 wall-clock 超时与取消机制
- 服务器侧对
applyEditWithDiff(...)使用更保守的 budgets,或直接禁用 diff - 不要把
raw直接当作可信 HTML / DOM 片段 - 不要让终端用户直接控制
handlers、syntax、tagName、createId或tracker - 监控
full-fallback频率、异常大 dirty span、异常延迟与异常 heap 增长,并把它们视为资源告警信号
许可证
本项目基于 MIT 许可证 发布。安全修复以尽力而为方式提供。