HarmonyOS ArkUI TextInput × Node.js:碰一碰交接清单摘要漂移与重放识别【鸿蒙心迹】
示例项目:ManifestDigest / MD-407
技术范围:ArkUI TextInput、Node.js crypto、Share Kit 数据接收后的业务层校验
一、接收成功,不代表清单可以直接入库
一个跨端交接场景里,清单看上去很简单:两台设备交换待处理文件的编号、数量以及业务批次。用户真正关心的是接收后有没有少项、相同清单是否被反复处理。若把一段收到的 JSON 原样塞进数据库,发送方改了条目数量、重发了同一个批次,接收页仍可能显示“成功”。这不是“碰一碰距离够近”能解决的问题,而是数据在到达应用业务层之后如何自证一致性的问题。
输入是事先写好的四份示例清单,展示层借 ArkUI TextInput 表示人工粘贴内容的入口;真正执行摘要校验的是可本地运行的 Node.js 工具。把系统传输和业务入库明确拆开,既能说明边界,也便于用同一批测试数据复现每一次判定。
任务号固定为 MD-407。示例中的 PK-71、PK-72、PK-73 是示例业务包号。第一份 PK-71 通过,PK-72 通过,PK-73 的声明摘要与条目内容不一致,同一份 PK-71 再次提交则命中重放识别。这四条构造输入最终应得到 GOOD 2、DRIFT 1、REPLAY 1。

二、先明确什么参与摘要,什么不能参与
摘要计算最容易遗漏的不是 SHA-256,而是同一份业务清单到底怎样转换为字节。JSON 对象字段顺序不同、客户端附加展示字段、数量由数字误变为字符串,都可能让原本相同的数据计算出不同结果。如果把原始文本的空格和字段顺序也包含进摘要协议,不同系统的序列化习惯很容易造成误判。示例采用固定字段投影,保留 id 和整数 qty,按照条目 ID 排序后统一做 UTF-8 JSON 序列化。
这是项目双方明确约定的简单规范,不是通用 JSON 规范化标准。它适用于本例条目 ID 使用 ASCII、每个 ID 唯一的前提;中文键名或复杂嵌套结构必须另行确定规范。对输入先做类型检查也很重要:数量负值或小数、数组缺失、ID 重复都不允许以“空内容”参与哈希运算。
下面代码解决“同一业务语义生成可重复摘要”的问题。完整可执行版本放在 examples/ManifestDigest/tools/digest-check.mjs 中,文章摘录关键部分:
import { createHash } from 'node:crypto';
function digest(items) {
const sorted = items.map(x => ({ id: x.id, qty: x.qty }))
.sort((a, b) => a.id.localeCompare(b.id, 'en'));
return createHash('sha256')
.update(JSON.stringify(sorted), 'utf8').digest('hex');
}
代码的输入是业务条目数组,输出是 64 位十六进制摘要文本。localeCompare 的稳定前提已经在输入合同中明确;在真实项目里不能悄悄替换排序规则。摘要只能证明当前内容与一个可信的期望摘要相同。如果攻击方可以同时篡改内容和声明摘要,二者依然能够匹配,所以哈希不等于来源认证,也不等于数字签名。需要认证发送方时,应使用经过密钥管理的消息认证码或签名协议,而不是把裸 SHA-256 当签名。
三、摘要漂移与重复业务包必须分开判断
校验顺序有现实意义。系统收到包后应先确认结构和摘要是否有效,之后再看这个包号是否已经成功处理。否则一条被篡改的旧包可能被简单标为“重复”,掩盖真正的数据异常。只有 GOOD 的包才写入已接收集合;DRIFT 的包不占用业务包号,避免发送方补发正确清单后被错误地拒绝。
下面的状态分支针对四份构造数据形成可核对的输出。这里使用 Set 作为一次脚本运行期间的示例账本,方便讲清判定顺序。
const seen = new Set();
for (const packet of batch) {
const actual = digest(packet.items);
let status = 'GOOD';
if (actual !== packet.digest) status = 'DRIFT';
else if (seen.has(packet.id)) status = 'REPLAY';
else seen.add(packet.id);
console.log(`MD-407 ${packet.id} ${status}`);
}
这个 Set 并不等于生产级去重表。应用退出后内存会消失,多进程并发还可能同时通过 seen.has。面向正式业务,应当在数据库中为业务包号或“发送端身份+包号”建立唯一约束,并以事务方式写入;需要重新处理合法更新时,最好使用修订号以及明确的覆盖规则,而不是永远拒绝同一 ID。对于已经接收成功的包,也要给出可查的回执,避免客户端网络超时后不知道是否真正落库。
1. 页面层只管理输入与展示
TextInput 的价值是把“用户正在编辑的数据”和“通过验证的数据”分离。开发页面可以展示原始输入框、校验按钮及状态列表,但不能把输入框里出现了合法 JSON 当作已经完成接收。下面是与示例图相对应的简化 ArkTS 入口,按钮只触发业务层样例提示。
@Entry
@Component
struct Index {
@State raw: string = '';
@State message: string = '等待本地清单校验';
build() {
Column({ space: 16 }) {
Text('交接清单摘要校验 MD-407')
TextInput({ placeholder: '粘贴业务清单 JSON', text: this.raw })
.onChange((value: string) => { this.raw = value; })
Button('回放校验样例')
.onClick(() => { this.message = '请查看 Node.js 构造数据结果'; })
Text(this.message)
}.padding(20)
}
}
这里的 raw 只保存可编辑文本;message 只是界面说明,并没有把 Node.js 运行代码伪装成 ArkTS 系统调用。真实应用若要对接后端校验服务,需要再处理发送请求时的重复点击、请求超时、页面退出以及回调过期等问题。接收者有权取消或拒绝清单,拒绝后的本地暂存信息也应按业务保留策略清理。

四、用一份可重复的样本检查结果
随包的 manifests.json 包含四条输入:PK-71 的摘要来自两条文件记录,PK-72 来自另一条记录;PK-73 在填写声明摘要时故意使用与实际内容不符的值;最后再提交与首次一致的 PK-71。运行 node tools/digest-check.mjs,按顺序应出现 GOOD、GOOD、DRIFT、REPLAY 四条日志,汇总 MD-407 GOOD=2 DRIFT=1 REPLAY=1。我在打包前使用 Node.js 对这些构造数据执行了脚本,并保存了 run.log,这与设备上的实时分享回调无关。
调试时不能只看汇总数量。首先确认用于计算摘要的 id/qty 数组与文件中的内容一致;其次检查 PK-73 是否在摘要阶段被拒绝;最后确认第二次 PK-71 不会生成第二条入库记录。如果未来把脚本移植到 ArkTS,摘要字节规则、大小写处理和错误处理必须保持一致,不能单独更改其中一端的规范化实现。

五、容易被结果界面掩盖的两个风险
其一是内容完整性与身份真实性被混为一谈。即使摘要正确,清单也可能由一个无权的发送者构造。生产环境应该设计发送者身份、授权范围、失效期和签名验证;本篇只提供摘要漂移与同一进程内的重放识别。其二是文件 ID 与实际文件内容并不自动绑定。如果交接的是图片或文档,还要确认文件字节摘要与 manifest 中的声明一致,并在沙箱内完成安全复制;本篇只校验清单的结构内容,不校验远程文件。
华为 Share Kit 官方接收文档说明应用可通过系统分享入口获取分享数据,长期编辑的图片或文件建议复制到自己的沙箱目录。也就是说,平台层的接收方式和本文业务层的摘要判定本来就是两步。也不能把其他应用的沙箱物理路径直接当作本应用可读文件。
当清单量增大时,排序哈希会消耗额外内存;长列表可以考虑分批编码、流式摘要,但前提仍是两端采用同一确定性格式。日志只需要保留包号、状态、摘要前缀以及明确脱敏后的错误原因,不宜把可能含个人信息的业务内容完整打印到 HiLog。数据处理完成后,应及时释放暂存缓冲、关闭文件句柄,并按照保留周期销毁敏感样本。
六、结论落在业务状态而不是动画效果
ManifestDigest 交付的不是跨设备 SDK 封装,而是一套可以运行、可以质疑的业务校验边界:GOOD 表示内容与期望摘要一致且该批次尚未接受;DRIFT 表示声明摘要与内容不同;REPLAY 表示已经接受过的相同批次再次出现。对错误输入不给模糊的“提交失败”,而是返回可追踪的状态。
后续要接入真实系统分享,需要另行验证 URI 来源与访问权限、签名或认证机制、持久化事务去重、重发策略与设备生命周期。配图是分别制作的开发界面和手机页面示意。保留这些边界后,业务交接才不会因一次成功的视觉反馈而隐藏数据一致性问题。
官方资料: https://developer.huawei.com/consumer/cn/doc/harmonyos-faqs/share-kit-faq-0001 ;https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-v5/share-mobilephone-app-share-V5
更多推荐


所有评论(0)