【HarmonyOS 7新能力|035】星盾机密风控工程封装:把接入逻辑放进可维护的分层结构
【HarmonyOS 7新能力|035】星盾机密风控工程封装:把接入逻辑放进可维护的分层结构

端侧风控的价值,是在尽量少暴露原始数据的前提下,把多个弱信号组合成可执行的风险判断。但“在端侧完成”并不天然等于安全:若页面随意读取设备信息、规则散落、结果不可解释,系统仍会产生权限扩大、误判和审计困难。本文围绕星盾机密风控场景,讨论如何把信号采集、机密计算、策略决策和业务处置隔离成可维护链路。
边界说明:本文的接口和类型是工程教学抽象,并非 HarmonyOS SDK 的真实签名。具体能力名称、支持版本、权限、数据处理约束和接入方式,应以目标 SDK 与华为官方文档为准。风控只降低风险,不能承诺绝对安全。
1. 从威胁模型开始,而不是从可采集字段开始
需求评审时最容易问“系统能给哪些信号”,正确的第一问应是“要阻止什么损害”。例如敏感文件外发、异常身份切换、批量自动操作,它们需要的证据完全不同。先定义受保护资产、攻击路径、允许的误报范围和失败后的业务动作,才能判断某个信号是否必要。
export interface RiskScenario {
id: string
protectedAsset: 'document' | 'credential' | 'operation'
consequence: 'observe' | 'challenge' | 'block'
maxDecisionMs: number
allowDegradedMode: boolean
}
场景模型不保存用户原始内容,只记录决策所需的业务边界。每新增一个采集项,都应能回答它服务于哪条风险假设、保留多久、缺失时如何处理。
2. 四层架构控制信任边界

业务页面只提交操作意图和必要上下文;风险编排层组织评估流程;能力适配层调用经过核验的平台能力;机密状态仓库保存规则版本、脱敏特征和决策审计。页面不接触密钥、原始凭据或底层设备标识,仓库也不反向依赖 UI。
export interface RiskEnginePort {
evaluate(input: MinimalRiskInput): Promise<RiskDecision>
}
export interface AuditPort {
append(record: SafeAuditRecord): Promise<void>
}
平台能力变更被限制在适配层,业务策略变化集中在编排层。测试时可以替换端口,构造正常、缺失和异常结果,而不需要在每个测试里启动真实安全能力。
3. 输入必须遵守数据最小化
风险引擎不应接收一个包罗万象的页面对象或 Context。先在调用侧生成最小输入:场景、动作、非识别性会话标记、经过本地转换的特征和规则版本。能用布尔特征就不传原文,能用区间就不传精确值,能即时计算就不持久化。
export interface MinimalRiskInput {
scenarioId: string
action: string
sessionNonce: string
features: Record<string, boolean | number | 'unknown'>
policyVersion: string
}
unknown 必须是一等状态。把“无法获得”默认为安全,会让权限拒绝或能力异常成为绕过路径;默认为高危又会制造大量误拦。它应该进入场景特定的降级规则。
4. 信号采集器只产出特征
采集器负责检查能力可用性、执行最小调用并转换结果,不决定是否阻断业务。每个采集器声明用途、超时和数据分类,编排器根据场景选择需要的集合,避免所有场景默认全量采集。
export interface SignalCollector {
readonly key: string
readonly purpose: string
collect(ctx: SignalContext): Promise<SignalResult>
}
export type SignalResult =
| { status: 'available'; value: boolean | number }
| { status: 'unavailable'; reason: string }
| { status: 'timeout' }
采集失败不能抛到页面形成白屏,而应转为结构化状态。敏感错误只记录归一化代码,不记录原始载荷、令牌或可识别信息。
5. 风险融合不是简单相加

多个信号可能相关:设备环境异常与会话异常同时出现,不一定代表两份独立证据。简单加权相加会重复放大风险。工程上可把规则分为硬约束、组合规则和修正项,并明确冲突优先级。
export interface RiskRule {
id: string
priority: number
when: (features: Readonly<RiskFeatures>) => boolean
effect: { delta: number; reasonCode: string }
}
function fuse(base: number, rules: RiskRule[], f: RiskFeatures): number {
return rules
.sort((a, b) => b.priority - a.priority)
.filter(rule => rule.when(f))
.reduce((score, rule) => clamp(score + rule.effect.delta, 0, 100), base)
}
示例分数仅表达结构,不代表官方模型或推荐阈值。生产阈值必须经真实数据、隐私评审和误报评估确定,并支持安全回滚。
6. 决策结果要可解释且有限
风险引擎输出不应只是一个数字。业务需要知道等级、允许动作、原因代码、规则版本和有效期。原因代码面向程序与审计,用户提示则由产品层转成易懂且不过度泄露防护细节的文案。
export interface RiskDecision {
level: 'normal' | 'suspicious' | 'high'
action: 'allow' | 'challenge' | 'deny'
reasonCodes: string[]
policyVersion: string
expiresAt: number
}
不要把底层信号值直接展示给用户,也不要用模糊的“系统错误”掩盖所有拦截。安全提示应说明下一步,例如重新确认、稍后再试或联系管理员。
7. 策略执行器坚持最小干预
风险决策与业务处置仍应分离。相同的 suspicious 在查看公开资料时可能只观察,在导出机密文件时则需要二次确认。执行器结合场景策略选择动作,并保证失败可恢复。
export async function enforce(
decision: RiskDecision,
command: ProtectedCommand
): Promise<CommandResult> {
if (decision.action === 'deny') return { status: 'blocked' }
if (decision.action === 'challenge') return challengeThenRun(command)
return command.run()
}
阻断、删除、清除凭据等高影响操作不能仅凭单一弱信号自动执行。优先选择限制本次操作、缩小权限或增加验证,并向用户提供清晰出口。
8. 机密状态仓库保存什么
仓库适合保存已生效规则版本、非识别性决策记录、限时缓存和回滚指针,不适合变成原始信号的永久集中地。记录应有明确 TTL,应用卸载、账号退出或业务撤销时按设计清理。
export interface SafeAuditRecord {
eventId: string
scenarioId: string
decision: RiskDecision['action']
reasonCodes: string[]
policyVersion: string
occurredAt: number
}
审计记录不要包含文件内容、用户输入、完整设备标识或认证秘密。若确需跨端同步,必须重新评估数据分类、用户告知、加密和服务端边界,不能因为已有仓库就顺手上传。
9. 并发、超时与幂等
同一用户操作可能因重复点击产生并发评估。以 eventId 作为幂等键,相同操作共享进行中的 Promise 或复用短期有效决策。不同采集器可在允许范围内并行,但整体必须有超时预算。
async function evaluateWithBudget(input: MinimalRiskInput): Promise<RiskDecision> {
const cached = await decisionCache.get(input.sessionNonce)
if (cached && cached.expiresAt > Date.now()) return cached
return withTimeout(engine.evaluate(input), scenarioBudget(input.scenarioId))
}
超时后的动作由场景决定:低风险场景可降级放行并记录,高风险场景可要求稍后重试。不要用一个全局默认值覆盖全部业务。
10. 规则版本化与灰度回滚
规则调整可能比代码发布更频繁,但动态规则也不能成为不可审计的远程执行入口。规则格式需要白名单字段、严格类型、签名或可信来源校验、版本兼容检查,并限制为声明式条件。
export interface PolicyBundle {
version: string
schemaVersion: number
activatedAt: number
rules: readonly SerializedRule[]
}
激活新版本前先验证完整性和兼容性,失败则继续使用最近一次有效版本。审计记录同时保存 policyVersion,才能在误报发生后复现当时决策,而不是用最新规则猜测历史结果。
11. 测试覆盖安全与可用性
单元测试要覆盖正常、可疑、高风险、信号缺失、采集超时、规则冲突、旧版本回滚和重复事件。契约测试验证适配器只输出允许字段。真机测试关注权限拒绝、应用前后台、低资源、离线、时间变化以及核心流程是否仍可达。
it('does not treat a missing signal as false', async () => {
const result = await collector.collect(deniedPermissionContext)
expect(result.status).assertEqual('unavailable')
})
还要检查日志与崩溃报告,确认其中不包含原始敏感数据。测试报告应分别记录“规则行为符合预期”和“目标设备平台能力可用”,二者不能互相代替。
12. 落地检查与总结
上线前逐项确认:威胁模型明确;每个信号有合法用途和最短生命周期;输入完成最小化;页面无法读取机密数据;规则可解释、可版本化、可回滚;重复请求幂等;超时有场景化降级;审计不包含敏感原文;权限、隐私说明和实际行为一致;目标设备完成关键流程测试。
星盾机密风控的工程重点,不是堆叠更多采集能力,而是建立一条窄而清楚的信任链。业务只提交必要意图,采集器只产出最小特征,融合器只做确定规则,执行器实施有限动作,仓库留下安全审计。当任一平台能力或策略变化时,影响都被约束在对应层中,安全性与可维护性才能同时成立。
本文为 HarmonyOS 7 新能力工程实践系列第 035 篇。示例仅用于架构说明,实际项目请依据官方文档、目标 SDK、隐私政策和安全评审结果落地。
更多推荐


所有评论(0)