浏览器导入日志的边界验收:UTF-8、字节上限与失败关闭

举报
yd_234095983 发表于 2026/10/24 19:33:19 2026/10/24
【摘要】 基于真实浏览器六组虚构文件导入实验,核对 UTF-8 严格解码、1 MiB 字节边界、空字节拒绝及失败时禁用导出;区分实测范围与安全保证。

作者:lgbisha。本文使用 AI 辅助整理,基于本人已公开项目「隐迹 · 离线日志脱敏」1.0.0 的实际源码和 2026 年 10 月 24 日浏览器实测。所有输入均为专门生成的虚构文本或字节,不含真实日志和有效凭据。

上一篇介绍替换区间与结果失效,这次只讨论更早的一道入口:浏览器选择文件之后,什么内容可以进入文本处理流程?文件后缀正确不等于编码正确,字符数量也不等于文件字节数。入口如果悄悄修复或截断输入,后续处理即使正常运行,也可能处理了另一份内容。

一、把导入契约写成可检查的顺序

项目中的文件导入位于 assets/app.js,规则层的输入检查位于 assets/redactor.js。当前顺序是:

  1. 用户主动选择文件,使旧结果和导出状态失效。
  2. 检查 file.size,超过 1 MiB 即拒绝,不先读取整个文件再判断。
  3. 调用 file.arrayBuffer() 读取字节,并核对读取期间页面版本是否改变。
  4. 用 new TextDecoder("utf-8", { fatal: true }) 解码;非法 UTF-8 明确报错,不把替代字符当成原文。
  5. 把解码结果交给 validateInput,再次检查文本边界,包括空字节。
  6. 仅在全部通过后填入原始日志框。导入成功仍不是脱敏成功,需要用户另行执行处理。

其中关键部分可以简化为:

if (file.size > MAX_INPUT_BYTES) {
  throw new Error("文件超过字节上限");
}
const buffer = await file.arrayBuffer();
const decoded = new TextDecoder("utf-8", { fatal: true }).decode(buffer);
validateInput(decoded);

这段示意省略了界面更新和异步版本校验,不能直接替换项目完整函数。入口也不靠 MIME 类型或 .txt 后缀证明文件一定是纯文本。

二、1 MiB 限的是字节,不是 JavaScript 字符串长度

本项目的上限为 1,048,576 字节。恰好等于上限允许导入,大于上限才拒绝。这使边界测试至少需要覆盖上限前后,而不是只试一个很小的英文文件。

本次还准备了 349,526 个“中”字:其 UTF-8 编码共 1,048,578 字节,虽然字符数量明显少于一百万,仍然超过上限。浏览器实际显示“文件超过 1 MiB”。

可用以下 Node.js 代码复核测试数据的字节数,不需要任何真实文件:

const text = "中".repeat(349526);
console.log(text.length);
console.log(Buffer.byteLength(text, "utf8"));

本次输出分别为 349526 和 1048578。文件导入前检查的是文件字节数,输入框计量也应使用 UTF-8 字节长度,不能直接把 text.length 当作字节数。

三、非法编码和空字节是两类拒绝

第一种测试输入只有两个字节:0xC3 0x28。它不是合法 UTF-8。当前严格解码会失败,界面提示“文件不是有效的 UTF-8 文本,请转换编码后重新导入”。这比默默生成替代字符更便于用户发现文件编码问题。

第二种输入是 demo、一个 0x00 字节和 end,共 8 字节。它能被 UTF-8 解码,但违反本工具的纯文本输入契约,后续检查提示“内容包含空字节,请使用 UTF-8 纯文本文件”。

因此,“解码成功”不等于“输入校验成功”。这里拒绝空字节是本工具的产品选择,不是说 UTF-8 本身禁止该码位,也不是通用恶意文件检测。

四、六组真实浏览器结果

2026 年 10 月 24 日,我用本机回环地址提供未修改的静态项目,在当前 Chromium 会话中通过文件选择控件导入以下合成文件。每组测试前清空页面,完成后核对提示、原文框与两个导出按钮。

输入 文件字节数 导入结果
含中文与虚构 password 字段的合法 UTF-8 39 接受,等待用户执行脱敏
字节 C3 28 2 拒绝:不是有效 UTF-8
demo + 空字节 + end 8 拒绝:包含空字节
超过上限的 ASCII 1,048,577 拒绝:超过 1 MiB
恰好达到上限的 ASCII 1,048,576 接受,等待用户执行脱敏
349,526 个“中”字 1,048,578 拒绝:超过 1 MiB

六组结果均符合本次预期。四组被拒绝的输入没有写入原文框;两组被接受的输入也没有直接变成可导出结果。所有组结束时,“复制结果”和“下载 .txt”均为禁用,因为测试没有执行脱敏。

这里的“六组”仅指文件导入场景,不是新增六条引擎单元测试,也没有重新宣称整套单元测试数量。恰好上限的样例只验证导入接受,不证明最大输入下的脱敏性能。

五、失败关闭需要连同界面状态一起验证

错误提示正确还不够。如果界面报“编码不合法”,却仍保留上一份可导出的结果,用户可能继续复制旧内容。因此本次验收同时记录了原文是否填入、复制是否禁用以及下载是否禁用。

项目在导入开始时就使旧结果失效,并在异步读取后比对页面版本。如果读取期间用户改动输入,过期回调不应覆盖新的状态。这一机制与字节、编码检查解决不同的问题:前者防止时序覆盖,后者约束当前输入。本文六组测试没有人为延迟文件读取,因此没有把异步竞争场景算作已实测通过。

六、“本地处理”的证据要说明观察窗口

在本次六组交互开始后,我监听了该页面发起的网络请求,交互结束后停止监听;观察窗口内记录为零条请求。这能支持“本次文件导入没有观察到页面新发出的网络请求”,不能外推为对浏览器扩展、操作系统、剪贴板或所有未来版本的安全审计。

静态资源在开始观察前已加载。离线工具仍须检查实际运行的源码和来源,不能仅凭页面写着“不上传”就放入生产凭据。输入边界校验也不等于脱敏覆盖率保证;最终输出仍需按分享对象人工复核。

结语

文本工具的入口应明确区分文件字节、解码结果和业务允许的文本。对超限、编码错误和空字节分别给出可操作提示,且在失败时关闭导出通道,比“能打开一个正常文件”的验收更完整。

项目公开于 GitCode:LGBISHA/offline-log-redactor。本次未修改产品代码,没有使用真实凭据,也没有把一次浏览器测试写成全面安全保证。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。