拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

HarmonyOS 7 新特性实战(27):数字盾可信确认的文本校验与令牌接入

HarmonyOS 7 新特性实战(27):数字盾可信确认的文本校验与令牌接入

用户在确认窗口里看到“签署展品借阅凭证”,服务端却收到另一份内容的签名,这种问题无法通过给按钮加锁图标解决。可信确认最核心的要求,是用户看见、明确同意和最终验证的内容保持一致。

数字盾相关能力强调可信界面、输入与签名保护。实验使用一份无实际法律效力的测试凭证。公开能力介绍不等于所有应用已经具备调用资格;在具体接口与接入资质确认前,不用普通弹窗或旧版密钥接口冒充数字盾调用。

先确定签名对象的唯一表达

同一业务内容可能有多种 JSON 表达:字段顺序不同、空字段省略、日期格式不同,都可能产生不同字节。客户端与服务端应选择一致的规范化规则,对最终字节计算摘要。

凭证编号、展品编号、借阅期限、动作类型和挑战值都需要纳入保护范围。界面展示的友好名称可以保留,但不能只签名称而忽略唯一编号。以下为应用自己的待确认结构。

interfaceTestReceipt{schemaVersion:number;receiptId:string;exhibitId:string;action:'acknowledge-test-receipt';validUntil:string;challenge:string;}

序列化算法应有固定测试向量。遇到未支持的版本直接拒绝,不在接收端默默补默认值后继续验证。测试材料明确标注模拟用途,避免让体验者误以为正在签署真实凭证。

可信界面承担什么职责

应用普通页面负责说明业务上下文,可信确认环节负责呈现实际待确认的重要信息并获取用户操作。两者之间不能隐藏关键差异,例如普通页面说“查看”,最终动作却是“授权”。

当系统可信界面对文本长度、字段类型或交互方式有约束时,应按文档映射业务信息。不能通过截断文本隐藏关键内容,也不能把所有信息塞进无法辨识的摘要后声称用户已理解。

需要系统证明的内容必须来自真实能力返回。普通 ArkUI 对话框只能验证业务流程和取消行为,不能证明可信输入、受保护显示或安全硬件参与了签名。

用户取消是正常结果

确认流程至少区分等待、成功、取消、失败和过期。取消后不自动再次拉起;失败重试时重新检查挑战是否仍然有效。应用切到后台后收到回调,也不能直接改变已经关闭的业务页面。

每次任务绑定唯一 requestId。旧任务完成时,只有当前业务仍等待同一个请求,才能消费结果。签名材料保存时间应尽可能短,日志里不记录可复用的完整结果。

如果用户在确认期间编辑了凭证内容,应使当前确认失效。不能把旧摘要对应的签名挂到新版本凭证上。服务端以签名覆盖的版本作为唯一依据。

服务端验证不能省略上下文

验证端首先按官方要求检查可信来源与签名,再核对凭证内容、挑战、动作和期限。密钥可信不等于任意业务都被授权;另一个场景产生的签名不能直接用于当前操作。

挑战的消费与凭证状态变更需要一致性保护。若网络在成功后中断,客户端重试应得到同一业务结果,不能创建第二份凭证。这里的幂等键属于业务协议,不能拿设备标识替代。

安全硬件保护私钥与业务语义正确是两层问题。即使密钥无法导出,错误的字段映射仍然可能让用户确认错误内容,因此字段一致性测试必须独立存在。

验收用例围绕内容变化展开

先签署固定测试凭证,再逐项修改展品编号、动作、期限和挑战,确认旧签名无法被接受。随后覆盖取消、超时、重复提交、旧页面回调和设备能力不可用。

对可信界面的验收需要支持设备和官方接入链路。录屏可以辅助说明用户看见什么,但不能单独证明安全能力执行成功;还需要脱敏的请求关联、验证结果及设备环境。

在接口未确认阶段,Demo 可以完成规范化测试、业务状态机和验证端契约。它们应被标为流程原型。取得实际能力后,再补系统调用和真实验签,才能把文章升级为完整接入实战。

让确认内容变化成为独立测试向量

修改内容需要验证的结果
只改变无语义的序列化字段顺序按选定规范化规则得到一致字节
改变展品或动作得到不同待签内容,旧结果不可复用
新挑战替换旧挑战旧确认不完成新请求

直接签任意 JSON 实现较短,但双方规范不一致时难以定位失败;固定版本的规范化契约增加前置工作,能把签名争议落到具体字节。先用固定向量核对规范化,再实现取消与幂等,最后接可信界面和正式验证。普通弹窗仅承担前两个阶段的流程调试。

参考:华为开发者能力介绍。数字盾具体版本、开放范围及可信界面接口需另行核实;旧有密钥存储或普通签名接口不能代替数字盾能力。

可信文本、挑战与认证令牌的归属

可信确认前先检查文本排版。结果非零时停止调用,保留不能展示的位置。确认入口需要已有 authID、合法图片和 32 字节挑战;挑战来自 HUKS 会话初始化,不自行生成一个随机数替代。

PIN 认证路径把相同文本放入 authContent,避免展示内容与认证内容分叉。用户取消和 SDK 错误向调用方传播,不返回成功令牌。页面只显示令牌字节数,不把完整令牌输出到日志。

exportclassTrustedProbe{asynccheckText(text:string):Promise<trustedAuthentication.TextCheckResult>{returntrustedAuthentication.checkConfirmUITextFormat(InputRules.required(text,'confirmation',2048));}asyncconfirm(challengeHex:string,authId:string,text:string,image:ArrayBuffer):Promise<trustedAuthentication.AuthToken>{constchallenge:Uint8Array=InputRules.hex(challengeHex);if(!/^[1-9][0-9]*$/.test(authId)){thrownewError('valid enrolled authID required');}InputRules.required(text,'confirmation',2048);if(image.byteLength===0){thrownewError('TUI label image required');}constchecked:trustedAuthentication.TextCheckResult=awaitthis.checkText(text);if(checked.result!==0){thrownewError('TUI format rejected at '+checked.lastIndex);}returntrustedAuthentication.procContentAuthentication(challenge,BigInt(authId),{reqType:trustedAuthentication.AuthType.AUTH_TYPE_TUI_PIN,authContent:[text]},{title:'图鉴测试确认',image:image});}}

辅助校验与边界处理使用以下实现:

exportclassInputRules{staticrequired(value:string,name:string,max:number=256):string{if(typeofvalue!=='string'||value.trim().length===0||value.length>max){thrownewError(name+' is missing or too long');}returnvalue.trim();}statichex(value:string):Uint8Array{if(!/^[0-9a-fA-F]{64}$/.test(value)){thrownewError('challenge must be 32 bytes of hex');}constbytes:Uint8Array=newUint8Array(32);for(leti:number=0;i<bytes.length;i++){bytes[i]=parseInt(value.substring(i*2,i*2+2),16);}returnbytes;}}

用排版失败和认证调用次数核对源码

数字盾登记、HUKS 会话和合法 TUI 图片,令牌用于后续 HUKS 操作的完整流程。

检查层当前处理不能替代的结果
编译API 26 工程进行类型检查与打包目标设备支持
逻辑校验输入、状态或资源释放边界平台服务真实返回
联调按上面的输入和条件逐步执行不能以按钮文案代替核心结果

可信认证与 HUKS 会话的版本约束,以 HarmonyOS 官方文档中心和当前 SDK 声明为准。

排版不合格时不会进入认证

可信文本排版检查失败,认证接口不得继续执行;通过断言认证调用次数可检查这一前置条件。合法挑战仍须来自实际 HUKS 会话。宿主测试直接载入 TrustedProbe,仅以替身代替 trustedAuthentication;load 与 test 属于测试框架。

test('trusted: rejected format never opens authentication',async()=>{letcalled=0;constC=load('services/TrustedProbe',{'@kit.DeviceSecurityKit':{trustedAuthentication:{checkConfirmUITextFormat:async()=>({result:1019100011,lastIndex:0}),procContentAuthentication:async()=>called++,AuthType:{AUTH_TYPE_TUI_PIN:32}}}}).TrustedProbe;awaitassert.rejects(newC().confirm('ab'.repeat(32),'1','text',newArrayBuffer(8)),/format/);assert.equal(called,0);});
操作或边界应检查的结果
输入不满足前提不调用后续平台操作
平台拒绝或抛错保留错误,不生成成功状态
再次进入或重试检查旧状态不会污染新任务
返回列表