当前位置: 首页 > news >正文

鸿蒙HarmonyOS AI 应用安全红线实战 —— API Key 管理、网络安全、工具安全、发布扫描

一、前言:AI 应用安全的"五条红线"

做 AI Agent 应用,有五条安全红线绝不能碰

  1. Key 不落盘:API Key 只在进程内存,永不写入文件/数据库/preferences/rawfile/日志。

  2. Key 不入 State:AgentState 持久化时,Key 绝不被序列化。

  3. HTTPS only:所有网络请求走 HTTPS,禁止明文 HTTP,禁止重定向到非 HTTPS。

  4. 工具最小权限:工具默认只读,危险操作需用户确认,ToolContext 不暴露 Key。

  5. 发布前扫描:HAP 包发布前必须通过密钥扫描,确认无泄漏。

这五条红线看似简单,但在实际工程中每一条都有自己的陷阱。ArkAgent 用 RuntimeCredentials + BearerTokenProvider + UrlUtil + scan-hap-secrets.sh + security-baseline.md 构建了完整的安全防护体系。


二、API Key 生命周期

2.1 RuntimeCredentials:内存专用持有器

ArkAgent 示例工程的RuntimeCredentialsentry/src/main/ets/session/RuntimeCredentials.ets)是 Key 管理的最佳实践参考:

/** * Keys live only in process memory. They are never written to filesDir, * preferences, rawfile, or logs. Call clearAll() on Ability destroy and * when the page tears down. */ export class RuntimeCredentials { private static instance?: RuntimeCredentials private zhipuApiKey: string = '' private deepseekApiKey: string = '' private zhipuModel: string = 'glm-5.2' // 模型 ID 非敏感 private deepseekModel: string = 'deepseek-v4-flash' static shared(): RuntimeCredentials { ... } /** Does not log, persist, or echo the value. */ setApiKey(provider: string, key: string): void { const trimmed = key.trim() if (provider === 'deepseek') { this.deepseekApiKey = trimmed } else { this.zhipuApiKey = trimmed } } /** Callers must not log, persist, or put this into AgentState / UI snapshots. */ getApiKey(provider: string): string { ... } /** Only returns "已输入(仅内存)" or "未输入" — never the key content. */ keyStatusLabel(provider: string): string { ... } /** Zero out keys. Call on Ability destroy. */ clearAll(): void { this.zhipuApiKey = '' this.deepseekApiKey = '' } }

2.2 Key 存储位置红线

位置

能不能存 Key

原因

rawfile/

打入 HAP,可被解包提取

preferences

明文存储在设备 filesDir

filesDir 文件

设备备份可被提取

AgentState

State 会被持久化到文件

日志(hilog)

日志可被收集

错误信息

可能显示给用户或记入日志

Git 提交

版本控制泄漏

进程内存

唯一允许的位置

2.3 页面集成中的密钥流转

// 用户输入 Key 后立即清空 UI 缓冲 private applyRuntimeKey(): void { SessionCoordinator.shared().setRuntimeApiKey(this.apiKeyInput) this.apiKeyInput = '' // ← 立即清空 this.refreshKeyStatus() } // 页面销毁清零 aboutToDisappear(): void { this.apiKeyInput = '' SessionCoordinator.shared().clearSecrets() }

Key 输入后立即清空 UI 输入框缓冲,不让 Key 在@State里多留一秒。

2.4 ⚠️ 踩坑一:rawfile 打包 Key 进 HAP

症状:阶段 9 验收发现 local key 可能进入 HAP——rawfile 会打包进应用资源,HAP 安装包里直接包含 Key 文件。

根因:如果把provider_keys.local.json放在entry/src/main/resources/rawfile/下,HAP 打包时会把它打入资源包。任何人解包 HAP 就能提取 Key。

修复

  • 禁止在 main rawfile 存放任何 key 文件

  • Key 只通过运行时密码输入(内存)

  • 发布前执行scan-hap-secrets.sh扫描 HAP 包

阶段 9 报告踩坑表记录:"local key 进入 HAP:rawfile 会打包进资源 → 禁止 main rawfile Key;运行时内存输入 + secret scan"。

2.4 ⚠️ 踩坑二:错误信息拼接 Authorization 泄漏

症状:网络请求失败时,错误信息里拼接了完整的请求头(含Authorization: Bearer xxx),日志收集系统记录了这个错误,Key 泄漏。

根因:错误处理代码直接把请求的 cause 信息透传给上层,没有做脱敏。HTTP 库的错误消息可能包含完整的请求 URL 和 Header。

修复:所有可能包含 Key 的错误信息都做Bearer ***替换:

// HarmonyHttpTransport 和 OpenAICompatibleClient 的错误处理 const sanitized = message.replace(/Bearer\s+[A-Za-z0-9._\-]+/gi, 'Bearer ***')

Eval 模块更进一步,用EvalSanitize.redactString做多模式脱敏:Bearer ***sk-***data:***;base64,***、签名 query、Basic ***


三、密钥注入:BearerTokenProvider

3.1 SPI 接口

export interface BearerTokenProvider { getToken(): Promise<string> } export class StaticBearerTokenProvider implements BearerTokenProvider { private readonly token: string constructor(token: string) { this.token = token } async getToken(): Promise<string> { return this.token } }

3.2 注入点

// OpenAICompatibleClient.buildHttpRequest const token = await this.config.tokenProvider.getToken() if (token.trim().length === 0) { throw ArkAgentError.config('missing_token', 'Bearer token is empty') } headers.set('Authorization', `Bearer ${token}`)

Core 不持久化 token——Token 通过 ProviderConfig 的 tokenProvider 注入,只在网络调用时取出使用,不进入 ModelConfig、不进入 AgentState、不进入日志。


四、网络安全

4.1 HTTPS only

// UrlUtil export function ensureHttps(url: string): Result<void, ArkAgentError> { if (!url.startsWith('https://')) { return Result.failure(ArkAgentError.security('https_required', 'Only HTTPS endpoints are allowed')) } return Result.success(undefined as void) }

每次请求/stream 前都调UrlUtil.ensureHttps校验——HarmonyHttpTransport 的validateRequest里做了这道门。

4.2 禁止重定向

security-baseline.md 明确:"禁止自动跟随非 HTTPS 或跨主域重定向"。HarmonyHttpTransport 没有任何followRedirect选项——系统 http 模块默认不跟随,且 security-baseline 禁止开启。

4.3 Proxy 硬失败

private ensureProxyNotConfigured(): void { if (this.config.proxyUrl !== undefined && this.config.proxyUrl.trim().length > 0) { throw ArkAgentError.config('proxy_unsupported', 'HTTP proxy is not supported by HarmonyHttpTransport; leave proxyUrl empty') } }

鸿蒙@ohos.net.http不支持应用层 HTTP 代理。设置 proxyUrl 是硬性配置错误(不静默忽略)。

4.4 错误信息脱敏

// HarmonyHttpTransport.mapTransportError // Never include authorization or bodies in cause. const sanitized = message.replace(/Bearer\s+[A-Za-z0-9._\-]+/gi, 'Bearer ***') return ArkAgentError.transport('http_transport_error', 'HTTP transport failure', ErrorRetryability.conditional, sanitized)

所有可能包含 Key 的错误信息都做了Bearer ***替换。OpenAICompatibleClient 的asError方法也做了同样的脱敏。


五、HeaderPolicy:敏感头脱敏

5.1 RESERVED headers

static readonly RESERVED: string[] = [ 'authorization', 'content-type', 'accept', 'host', 'content-length', 'transfer-encoding', 'connection', 'proxy-authorization' ]

RESERVED headers 不可被 custom headers 覆盖。mergeCustomHeaders撞到 RESERVED 名返回reserved_header错误——不静默丢弃,显式报错。

5.2 SENSITIVE 脱敏

static readonly SENSITIVE_NAME_HINTS: string[] = [ 'authorization', 'api-key', 'apikey', 'x-api-key', 'token', 'secret', 'password', 'cookie', 'set-cookie' ] static redactHeadersForLog(headers: HttpHeaders): JsonObject { // 匹配 SENSITIVE_NAME_HINTS 的 header → 值替换为 *** }

所有日志输出的 header 都经redactHeadersForLog脱敏。


六、工具安全

6.1 最小权限

security-baseline.md:

  • "Tool 默认最小权限;读、写、删除、支付、发送、系统设置分级。"

  • "危险 Tool 在 beforeToolCall 要求用户确认。"

6.2 ToolContext 不暴露 Key

"ToolContext 不暴露 API Key 和任意 Service Locator。"

ToolContext 只有:sessionId(只读 state)、batchCallId、signal、services(有限白名单 ToolServiceRegistry)。没有 Key、没有任意 Service Locator。

6.3 路径遍历防护

// safeSessionFileName // 拒绝空、..、/、\\、控制字符 // 非安全字符替换为 _

State 文件路径用safeSessionFileName校验,防止../../etc/passwd作为 sessionId 读取任意文件。


七、scan-hap-secrets.sh:发布前扫描

7.1 四类扫描

# scripts/scan-hap-secrets.sh # "Fails if any of the following appear in main resources or packaged HAP: # provider_keys.local.json... Authorization/Bearer headers with non-redacted material... # placeholder/sentinel key strings... # Does NOT print secret values. Hits are reported by path + pattern name only."

扫描类型

检查内容

main rawfile

provider_keys.local.json+ 禁getRawFileContentSync(...provider_keys...)

HAP 文件名

禁止含密钥文件名

placeholder/sentinel

REPLACE_WITH_ZHIPU_API_KEY/REPLACE_WITH_DEEPSEEK_API_KEY/arkagent-test-sentinel-key-do-not-ship

非脱敏 Bearer

Bearer [A-Za-z0-9._\-]+(容忍Bearer ***

7.2 验收证据

阶段 9 报告:"scan-hap-secrets.sh OK clean(主 HAP 无 local key 文件 / placeholder / 非脱敏 Bearer)"。


八、EvalSanitize:评测脱敏

Eval 模块的EvalSanitize.redactString做了多模式脱敏:

// Bearer *** (Authorization Header) // sk-*** (API Key 前缀 sk-) // data:***;base64,*** (Base64 数据) // 签名 query(Signature|X-Amz-Signature|token|access_token|Expires) // Basic *** (Basic Auth)

所有 Trace/Recording/Report 出口都经此脱敏——保证评测产物不泄漏敏感信息。


九、风险登记册

ArkAgent 的risk-register.md记录了 12 条风险:

ID

风险

严重度

状态

R-002

签名凭据进入版本控制

严重

开放

R-003

ArkTS 递归 JSON 类型

已缓解

R-004

HarmonyOS HTTP 流被缓冲

开放(SPI 逃生通道)

R-005

Provider 兼容协议漂移

已缓解(90 天复验)

R-006

任意 JS 无安全沙箱

严重

1.0 不实现(ADR-0012)

R-007

暂停恢复重复 Tool 副作用

严重

已缓解(配对 checkpoint)

R-009

reasoning/用户数据进入遥测

已缓解(脱敏)

R-010

Sub-agent 资源费用失控

开放(预算限制)

R-012

多模态大对象内存压力

开放(大小限制+URI)

关键设计:风险登记册不假装风险已解决——R-004(HTTP 缓冲)至今保持"开放"状态,用 Transport SPI 留逃生通道。这种"诚实面对未知"的工程态度是安全的基础。


十、security-baseline.md 发布门禁

6 条发布安全门禁:

  1. secret 扫描无高风险

  2. 危险 Tool 确认测试

  3. 路径穿越测试

  4. 脱敏测试

  5. 依赖许可证清单

  6. 在线 Provider 测试无请求内容泄漏


十一、最佳实践清单

密钥管理

  • ✅ Key 只在运行时内存输入(密码框),不写入任何持久化存储。

  • ✅ Key 输入后立即清空 UI 缓冲。

  • ✅ 页面 aboutToDisappear / Ability onDestroy 调用 clearAll()。

  • ✅ Key 通过 BearerTokenProvider 注入,不进入 ModelConfig/AgentState。

  • ❌ 不把 Key 写入 rawfile/preferences/filesDir/Git。

网络安全

  • ✅ 所有请求 HTTPS only(UrlUtil.ensureHttps)。

  • ✅ 禁止重定向到非 HTTPS。

  • ✅ Proxy 硬失败(不静默忽略)。

  • ✅ 错误信息 Bearer *** 脱敏。

工具安全

  • ✅ 工具默认最小权限。

  • ✅ 危险工具标 ToolRiskLevel.dangerous + 审批。

  • ✅ ToolContext 不暴露 Key/任意 Service Locator。

  • ✅ 路径参数用 safeSessionFileName 校验。

发布安全

  • ✅ 发布前跑 scan-hap-secrets.sh。

  • ✅ 日志 header 经 redactHeadersForLog 脱敏。

  • ✅ Eval 产物经 EvalSanitize 脱敏。

  • ✅ RESERVED headers 不可被 custom headers 覆盖。


十二、常见错误对照表

错误做法

问题

正确做法

Key 写入 rawfile

HAP 可被解包提取

运行时内存输入

Key 留在 UI @State

页面销毁前暴露

应用后立即清空

AgentState 存 Key

持久化泄漏密钥

State 只存可序列化非敏感数据

日志输出 Authorization

日志收集泄漏

Bearer *** 脱敏

错误信息拼接请求体

泄漏 prompt/Header

只显示错误码和简短说明

HTTP 明文传输

中间人攻击

HTTPS only

自动跟随重定向

钓鱼重定向

禁止重定向

proxyUrl 静默忽略

行为不可预测

硬性 config error

工具能访问 Key

Key 泄漏风险

ToolContext 不暴露 Key

危险工具自动执行

不可逆操作

ToolRiskLevel.dangerous + 审批

sessionId 不校验路径

路径遍历读任意文件

safeSessionFileName

发布不扫密钥

HAP 内残留 Key

scan-hap-secrets.sh


十三、验证清单

密钥

  • Key 输入后输入框立即清空

  • 退出页面后 Key 不保留

  • AgentState 持久化文件中无 API Key

  • 错误信息不含 Key / Authorization

  • 日志不含 Key / Authorization

网络

  • 所有请求 HTTPS

  • HTTP URL 被拒绝

  • 无重定向

  • proxyUrl 被拒绝

工具

  • ToolContext 无 Key

  • 危险工具触发审批

  • 路径参数防遍历

发布

  • scan-hap-secrets.sh 无命中

  • HAP 无 placeholder/sentinel

  • HAP 无非脱敏 Bearer

  • 设备 filesDir 无 Key 文件


十四、构建验证

# 构建后扫描 NODE_HOME=/Applications/DevEco-Studio.app/Contents/tools/node \ DEVECO_SDK_HOME=/Applications/DevEco-Studio.app/Contents/sdk \ /Applications/DevEco-Studio.app/Contents/tools/hvigor/bin/hvigorw assembleHap --no-daemon # 密钥扫描 bash scripts/scan-hap-secrets.sh
scan-hap-secrets.sh: OK clean

十五、写在最后

Key 只进内存不落盘,页面销毁就清零。 BearerTokenProvider 注入,State 日志永不存。 HTTPS only 不重定向,proxy 硬失败不留情。 错误信息不拼体,Bearer 星号来脱敏。 RESERVED 头不可盖,敏感头日志打星号。 工具最小权限走,危险操作要审批。 ToolContext 不露 Key,Service 白名单来把关。 sessionId 防遍历,safeSessionFileName 保平安。 发布之前扫密钥,scan-hap-secrets 不能少。 风险登记不假装,开放风险留通道。

本文是 ArkAgent 鸿蒙教程系列的第十四篇,也是最后一篇。从架构全景到快速接入,从流式输出到 JSON 类型安全,从工具调用到状态持久化,从控制安全到记忆子 Agent,从技能规划到评估框架,从测试策略到安全红线——十四篇文章构成了鸿蒙 AI Agent SDK 开发的完整知识体系。如果你正在鸿蒙上做 AI 应用,可以把这套架构和设计决策直接作为你的工程基线。

http://www.jsqmd.com/news/1209426/

相关文章:

  • 阿里云EMR StarRocks多模态混合检索引擎:原理、架构与应用实践
  • 2026企业网盘怎么选?我的选型经历与真实体会
  • 2026年图片转像素图的小程序推荐:亲测好用的免费方法 - 省事研究所
  • GAN SG-1魔方开箱评测:磁力SQ-1的性能突破与使用指南
  • 办公效率工具分享:鲲穹Word批量处理工具箱功能详解
  • PostgreSql学习第三篇
  • 电瓶车托运找什么物流?避坑指南与高效寄递全解析 - 快递物流资讯
  • RuoYi-Vue-Plus Docker 部署踩坑:MySQL 中文双重编码的根因与修复
  • Kubernetes 滚动更新导致 Nacos 服务瞬断?从 preStop 到优雅下线完整拆解
  • 【Figma AI组件变体实战指南】:20年UI架构师亲授5大高阶用法,90%设计师还不知道的智能变体工作流
  • QUAKE 3源代码评测:架构
  • 家里旧金饰怎么处理最划算?娄底人卖黄金的3种方式对比,第2种最坑! - 资讯在线
  • 2026有实力的亚洲EMBA测评榜单:民企老板择校避坑,重落地不镀金
  • 红米K40内核编译实战:从环境配置到刷机完整指南
  • 2026北京劳动纠纷法律服务选择指南 对比评估专业律师机构 - 产业观察报
  • java: Composite Pattern
  • Windows任务计划程序实现久坐提醒的简易教程
  • 国产FPGA盘古50K开发板硬件架构与应用解析
  • 玩物联网第 5 期:使用CH348芯片IO端口,控制红外灯和传感器报警
  • Ollama量化不是“选个参数就跑”:TensorRT-LLM兼容性矩阵、CUDA Compute Capability适配表、FP16/INT4混合精度决策树(限200人内部技术白皮书节选)
  • 大模型int4权重量化实战:GPTQ与AWQ算法原理与部署指南
  • JetBrains IDE集成Luma MCP实现AI视频工程化
  • AI 电锤智能功率 MOSFET 完整选型方案
  • 大抽数卫生纸哪家性价比高:联盛森宝足量划算 - MXyuyu
  • 2026北京劳务纠纷知名律师推荐:专业律所助力化解职场权益难题 - U渠道
  • Dify与RAG技术实战:构建企业级AI知识库
  • 阿里云EMR StarRocks多模态混合检索引擎:技术原理与应用实践
  • STM32嵌入式视觉开发:IPL人脸检测实战与资源优化指南
  • 天道阅读笔记
  • 泰格豪雅中国官方售后服务中心|服务电话与网点地址权威信息公示(2026年7月最新) - 亨得利官方服务中心