diff --git a/docs/source/tutorials/dos.md b/docs/source/tutorials/dos.md deleted file mode 100644 index f1363b921..000000000 --- a/docs/source/tutorials/dos.md +++ /dev/null @@ -1,60 +0,0 @@ ---- -title: DoS Prevention ---- - -When the template or data context cannot be trusted, enabling DoS prevention options is crucial. LiquidJS provides 3 options for this purpose: `parseLimit`, `renderLimit`, and `memoryLimit`. - -## TL;DR - -Setting these options can largely ensure that your LiquidJS instance won't hang for extended periods or consume excessive memory. These limits are based on the available JavaScript APIs, so they are not precise hard limits but thresholds to help prevent your process from failing or hanging. - -For the security boundary and production hardening guidance, see [Security Model][security-model]. - -```typescript -const liquid = new Liquid({ - parseLimit: 1e8, // typical size of your templates in each render - renderLimit: 1000, // limit each render to be completed in 1s - memoryLimit: 1e9, // memory available for LiquidJS (1e9 for 1GB) -}) -``` - -When a `parse()` or `render()` cannot be completed within given resource, it throws. - -## parseLimit - -[parseLimit][parseLimit] restricts the size (character length) of templates parsed in each `.parse()` call, including referenced partials and layouts. Since LiquidJS parses template strings in near O(n) time, limiting total template length is usually sufficient. - -A typical PC handles `1e8` (100M) characters without issues. - -## renderLimit - -Restricting template size alone is insufficient because dynamic loops with large counts can occur in render time. [renderLimit][renderLimit] mitigates this by limiting the time consumed by each `render()` call. - -```liquid -{%- for i in (1..10000000) -%} - order: {{i}} -{%- endfor -%} -``` - -Render time is checked on a per-template basis (before rendering each template). In the above example, there are 2 templates in the loop: `order: ` and `{{i}}`, render time will be checked 10000000x2 times. - -For time-consuming tags and filters within a single template, the process can still hang. For fully controlled rendering, consider using a process manager like [paralleljs][paralleljs]. - -## memoryLimit - -Even with small number of templates and iterations, memory usage can grow exponentially. In the following example, memory doubles with each iteration: - -```liquid -{% assign array = "1,2,3" | split: "," %} -{% for i in (1..32) %} - {% assign array = array | concat: array %} -{% endfor %} -``` - -[memoryLimit][memoryLimit] restricts memory-sensitive filters to prevent excessive memory allocation. As [JavaScript uses GC to manage memory](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_management), `memoryLimit` limits only the total number of objects allocated by memory sensitive filters in LiquidJS thus may not reflect the actual memory footprint. - -[paralleljs]: https://www.npmjs.com/package/paralleljs -[parseLimit]: /api/interfaces/LiquidOptions.html#parseLimit -[renderLimit]: /api/interfaces/LiquidOptions.html#renderLimit -[memoryLimit]: /api/interfaces/LiquidOptions.html#memoryLimit -[security-model]: /tutorials/security-model.html \ No newline at end of file diff --git a/docs/source/tutorials/security-model.md b/docs/source/tutorials/security-model.md index 6353ba1e6..838d8cbac 100644 --- a/docs/source/tutorials/security-model.md +++ b/docs/source/tutorials/security-model.md @@ -28,3 +28,18 @@ If you run an online service, avoid rendering fully user-defined templates whene - Prefer curated templates or a restricted template subset. - If user-defined templates are required, isolate rendering (worker/process/container), enforce OS/container memory and CPU limits, and apply request rate limits. - Treat `parseLimit`/`renderLimit`/`memoryLimit` as one layer in a broader DoS defense strategy. + +## DoS limits quick reference + +LiquidJS provides 3 DoS-oriented options: + +- [parseLimit][parseLimit]: limit total template size per `parse()` call. +- [renderLimit][renderLimit]: limit total render time per `render()` call. +- [memoryLimit][memoryLimit]: cooperatively limit memory-sensitive allocations counted by LiquidJS. + +For heavy single-template operations, process-level isolation is still recommended (for example with [paralleljs][paralleljs]). + +[paralleljs]: https://www.npmjs.com/package/paralleljs +[parseLimit]: /api/interfaces/LiquidOptions.html#parseLimit +[renderLimit]: /api/interfaces/LiquidOptions.html#renderLimit +[memoryLimit]: /api/interfaces/LiquidOptions.html#memoryLimit diff --git a/docs/source/zh-cn/tutorials/dos.md b/docs/source/zh-cn/tutorials/dos.md deleted file mode 100644 index e9930306d..000000000 --- a/docs/source/zh-cn/tutorials/dos.md +++ /dev/null @@ -1,58 +0,0 @@ ---- -title: 防止 DoS 攻击 ---- - -当模板或数据上下文不可信时,启用DoS预防选项至关重要。LiquidJS 提供了三个选项用于此目的:`parseLimit`、`renderLimit` 和 `memoryLimit`。 - -## TL;DR - -设置这些选项可以在很大程度上确保你的 LiquidJS 实例不会长时间挂起或消耗过多内存。这些限制基于可用的 JavaScript API,因此它们不是精确的硬性限制,而是确保你的进程不会失败或挂起的阈值。 - -关于安全边界和生产环境加固建议,请参见 [安全模型][security-model]。 - -```typescript -const liquid = new Liquid({ - parseLimit: 1e8, // 每次渲染的模板的典型大小 - renderLimit: 1000, // 每次渲染最多 1s - memoryLimit: 1e9, // LiquidJS 可用的内存(1e9 对应 1GB) -}) -``` - -## parseLimit - -[parseLimit][parseLimit] 限制每次 `.parse()` 调用中解析的模板大小(字符长度),包括引用的 partials 和 layouts。由于 LiquidJS 解析模板字符串的时间复杂度接近 O(n),限制模板总长度通常就足够了。 - -普通电脑可以很容易处理 `1e8`(100M)个字符的模板。 - -## renderLimit - -仅限制模板大小是不够的,因为在渲染时可能会出现动态的数组和循环。[renderLimit][renderLimit] 通过限制每次 `render()` 调用的时间来缓解这些问题。 - -```liquid -{%- for i in (1..10000000) -%} - order: {{i}} -{%- endfor -%} -``` - -渲染时间是在渲染每个模板之前检查的。在上面的例子中,循环中有两个模板:`order: ` 和 `{{i}}`,因此会检查 2x10000000 次。 - -单个模板内的标签和过滤器仍然可能把进程挂起。要完全控制渲染过程,建议使用类似 [paralleljs][paralleljs] 的进程管理器。 - -## memoryLimit - -即使模板和迭代次数较少,内存使用量也可能呈指数增长。在下面的示例中,内存会在每次迭代中翻倍: - -```liquid -{% assign array = "1,2,3" | split: "," %} -{% for i in (1..32) %} - {% assign array = array | concat: array %} -{% endfor %} -``` - -[memoryLimit][memoryLimit] 限制内存敏感的过滤器,以防止过度的内存分配。由于 [JavaScript 使用 GC 来管理内存](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_management),`memoryLimit` 仅限制 LiquidJS 中内存敏感过滤器分配的对象总数,因此可能无法反映实际的内存占用。 - -[paralleljs]: https://www.npmjs.com/package/paralleljs -[parseLimit]: /api/interfaces/LiquidOptions.html#parseLimit -[renderLimit]: /api/interfaces/LiquidOptions.html#renderLimit -[memoryLimit]: /api/interfaces/LiquidOptions.html#memoryLimit -[security-model]: /zh-cn/tutorials/security-model.html \ No newline at end of file diff --git a/docs/source/zh-cn/tutorials/security-model.md b/docs/source/zh-cn/tutorials/security-model.md index b9b2f7b5a..bb6a20f0b 100644 --- a/docs/source/zh-cn/tutorials/security-model.md +++ b/docs/source/zh-cn/tutorials/security-model.md @@ -28,3 +28,18 @@ LiquidJS 提供了面向 DoS 的限制选项(`parseLimit`、`renderLimit`、`m - 优先使用受控模板或受限模板子集。 - 如果必须支持用户自定义模板,请隔离渲染(worker/进程/容器),并同时配置操作系统或容器级的内存/CPU 限额与请求限流。 - 将 `parseLimit` / `renderLimit` / `memoryLimit` 视为 DoS 防护体系中的一层,而不是唯一防线。 + +## DoS 限制速查 + +LiquidJS 提供 3 个 DoS 相关选项: + +- [parseLimit][parseLimit]:限制每次 `parse()` 的模板总长度。 +- [renderLimit][renderLimit]:限制每次 `render()` 的总渲染时间。 +- [memoryLimit][memoryLimit]:协作式限制 LiquidJS 已记账的内存敏感分配。 + +对于单个模板中的重型操作,仍建议使用进程级隔离(例如 [paralleljs][paralleljs])。 + +[paralleljs]: https://www.npmjs.com/package/paralleljs +[parseLimit]: /api/interfaces/LiquidOptions.html#parseLimit +[renderLimit]: /api/interfaces/LiquidOptions.html#renderLimit +[memoryLimit]: /api/interfaces/LiquidOptions.html#memoryLimit