Skip to content

Security: CSJ608/TemplateFrame

Security

docs/SECURITY.md

文档输入安全与开发环境

本轮更新保留四个库的 netstandard2.0 / net462 / net8.0 兼容资产。样例及性能基准使用 net10.0;测试覆盖 net8.0 / net472 / net10.0。旧目标是编译兼容声明,实际部署应使用仍受支持且打过安全补丁的运行时。

开发与验证

global.json 要求系统安装 .NET SDK 10.0.402 或同 feature band 的更新补丁,不再优先使用仓库内的 SDK。CI 显式安装 SDK 8.0.426 和 10.0.402,以提供 .NET 8.0.32 和 10.0.13 测试宿主。

使用系统级命令验证环境与项目:

dotnet --info
dotnet restore TemplateFrame.slnx
./eng/audit-dependencies.ps1
dotnet build TemplateFrame.slnx -c Release --no-restore
dotnet test TemplateFrame.slnx -c Release --no-build --collect:"XPlat Code Coverage"
dotnet format TemplateFrame.slnx --verify-no-changes --no-restore

Linux 仅运行 -f net8.0 和 -f net10.0,net472 需要 Windows .NET Framework 环境。核验系统安装时应检查 dotnet --info 的 SDK Base Path 与 runtime 路径,避免把其他目录里的副本当成系统更新。此次系统安装与实际验证记录见 系统更新记录。

还原启用全部传递依赖审计,审计失败及高危/严重 NuGet 告警会阻断构建。eng/audit-dependencies.ps1 仅检查 solution 内的项目,校验 NuGet 漏洞索引时效并独立查询 OSV;已知有漏洞的旧版包作为阳性对照。OSV 命中、服务失败、结果不完整或阳性对照失败均阻断。过期 NuGet 数据源会明确告警,不能凭一次无告警还原放行。报告输出到忽略目录 artifacts/dependency-audit.json。

默认资源限额

Word、Excel 与 Excel.Simple 在打开输入包之前检查压缩字节数、包内条目数,以及读取每个 ZIP 条目时的实际展开量;随后用 OpenXML 的字符限额控制 XML part。校验不关闭调用方提供的流。图片读取及填入、表数据物化与行克隆也有独立预算。

TemplateResourceLimits 属性 默认值 作用范围
MaxInputBytes 64 MiB 输入 Office 包的压缩字节数
MaxPackageEntries 4,096 输入包内条目数量
MaxPackageEntryBytes 64 MiB 单个条目实际展开字节数
MaxExpandedBytes 256 MiB 整个输入包实际展开字节数之和
MaxXmlCharactersPerPart 16 Mi 字符 打开每个 XML part 时
MaxImageBytes 16 MiB 读取或填入的单张图片
MaxTableRows 100,000 一次数据操作的累计表格数据行数
MaxTableCells 1,000,000 一次操作的累计处理单元格数;Simple 也计表头
MaxClonedXmlCharacters 16 Mi 字符 填充时所有新增模板行副本的 XML 字符总量

默认限额会拒绝此前可能接受的超大文件。调整应基于业务容量、并发和可信程度,不能对外部输入无条件放开。参数必须大于零;TemplateResourceLimits.Default 不可变,每次操作单独累计预算,多个请求不共享计数。

using TemplateFrame.Engine;
using TemplateFrame.Word;
using TemplateFrame.Excel;
using TemplateFrame.Excel.Simple;

var limits = new TemplateResourceLimits
{
    MaxInputBytes = 32L * 1024 * 1024,
    MaxTableRows = 20_000,
    MaxTableCells = 200_000,
};

var options = new TemplateFillOptions { ResourceLimits = limits };
var wordEngine = new WordTemplateEngine(options);
var excelEngine = new ExcelTemplateEngine(options);

// 独立 Parser 保留原构造方式,也可显式配置资源预算。
var wordParser = new WordTemplateParser(limits, localizer: null);
var excelParser = new ExcelTemplateParser(limits, localizer: null);

// Simple 的直接读取和契约读写分别配置。
var table = SimpleExcel.Read(input, tableName: null, resourceLimits: limits);
var simpleOptions = new SimpleExcelOptions { ResourceLimits = limits };
var data = SimpleExcelContract.Read(input, contract, simpleOptions);

示例中的 input / contract 为调用方对象;若同一流连续使用,遵守对应 API 的位置约定,必要时归零。引擎上的限额通过 TemplateFillOptions 同时传给 Parse、Validate 和 Fill。直接使用 Validator 时可通过其 TemplateResourceLimits 构造器配置。

Simple 回读按实际存在的行排序处理,保留跳过全空行与重复行取首个的语义。标准 Excel 保留命名范围内的空行,因此会在分配返回结果之前检查范围预算。Excel 坐标必须落在 1–1,048,576 行、A–XFD 列内,范围需正向;格式上合法也不代表业务预算允许。共享字符串在一次解析内建立索引,避免每格反复遍历。

超限读/写抛 InvalidOperationException;Validate 将输入资源问题报告为 Invalid,不返回伪造的部分业务数据。行/单元格预算主要限制数据物化工作;Word Validate 的契约结构检查不等于完整 Parse,也不保证后续业务数据量一定可填。低层 Builder 面向受信任程序调用,不承担上传文档检查。

仍需由应用负责的边界

显式低内存 Excel 导入入口为 SimpleExcel.ReadStreaming、SimpleExcelContract.ReadStreaming 和 ExcelTemplateParser.ParseStreaming,旧集合接口不自动切换。新入口直接 ZIP/XML 读取,共享字符串正文/索引落盘,非 Seek 输入也暂存;配置已有 TemporaryDirectory、累计 MaxTemporaryBytes 和有界字符串缓存。单行/单个 SST 项与元数据分别设置有限 XML 字符预算,不因提高大文件限额而取消。模板图片仍受 MaxImageBytes 限制,诊断逐条回调不累计。详见两 Excel 包的 README。

同步回调可能在后续异常/取消前已经处理部分业务数据,事务与回滚由应用负责。库释放本次拥有的文件,不关闭调用方输入;临时内容可能含敏感数据,目录权限由宿主保护,不承诺加密、安全擦除或强杀/系统崩溃后零残留,也不扫描删除其他任务文件。新入口拒绝扫描到的重复/倒序行号,模板只识别显式行号;旧接口保留原排序/首值行为。流式解析不扫描未使用范围之后的全部工作表 XML,但 ZIP 实际解压预算预检仍覆盖所有条目。

这些限额是输入和工作量预算,不是进程峰值内存或执行时间的硬保证。应用应根据并发量配置限流、超时和任务隔离;服务端处理大文件时应避免在同一进程内无限并发。预检会实际读取展开内容,有额外 IO/CPU 成本;性能快照必须在新版本上重测。

Validate 校验模板契约,不进行活动内容净化。Fill 保留模板中的其他包内容,包括可能的宏、OLE、外部关系或旧图片资源。外部模板上传后再向他人分发的业务,需要独立的允许/拒绝策略;替换图片不能当作删除原始敏感字节。本库不执行宏或公式,也不主动获取外部关系 URL。

部署更新与源码升级分开验收:framework-dependent 应用更新实际宿主,self-contained 应用重新发布,容器重新构建并部署已修补镜像。开发机系统级更新不会替其他服务器或自包含应用打补丁。

There aren't any published security advisories