本节目标
- 掌握Universal Keystore Kit(HUKS)的密钥全生命周期管理能力,能够使用密钥生成、加密解密、签名验签等核心接口
- 掌握网络安全传输的核心机制,理解HTTPS证书链校验与双向认证的实现方式,能够正确配置Web组件网络通信安全
- 掌握权限最小化原则的落地方法,能够按照"声明→检查→申请→使用"的标准流程实现动态权限申请
- 掌握隐私合规的核心要求,能够正确配置隐私标签、隐私政策和权限使用理由,避免上架审核高频驳回问题
- 掌握ArkGuard字节码混淆的配置与使用,理解混淆选项的作用范围与局限性,能够正确配置白名单保留规则
- 能够为应用建立从数据加密、安全传输、权限管控到代码保护的完整安全防护体系
一、密钥管理与数据加密
1.1 Universal Keystore Kit概述
Universal Keystore Kit(密钥管理服务,简称HUKS)向业务/应用提供各类密钥的统一安全操作能力,包括密钥管理(密钥生成/销毁、密钥导入、密钥证明、密钥协商、密钥派生)及密钥使用(加密/解密、签名/验签、访问控制)等功能。
HUKS采用三层架构设计:SDK层 提供密钥管理接口供开发者调用,开发者可根据实际业务选择ArkTS或C API;HUKS服务层 实现密钥会话管理及存储管理;HUKS核心层承载核心功能,包括密钥的密码学运算、明文密钥的加解密、密钥访问控制等。对于具备安全环境(如TEE)的系统、设备,HUKS核心层必须运行在安全环境内。
核心原则:HUKS管理的密钥可以由业务/应用导入或调用HUKS的接口生成。密钥在全生命周期内,其明文仅在安全环境中进行访问操作,不会将明文传递出安全环境。
1.2 密钥生成与使用
以下示例展示使用HUKS生成AES密钥并进行加密解密的完整流程:
typescript
import { huks } from '@kit.UniversalKeystoreKit';
// 1. 配置密钥属性
let keyAlias = 'my_aes_key';
let properties: Array<huks.HuksParam> = [
{
tag: huks.HuksTag.HUKS_TAG_ALGORITHM,
value: huks.HuksKeyAlg.HUKS_ALG_AES
},
{
tag: huks.HuksTag.HUKS_TAG_KEY_SIZE,
value: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256
},
{
tag: huks.HuksTag.HUKS_TAG_PURPOSE,
value: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT |
huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT
},
{
tag: huks.HuksTag.HUKS_TAG_PADDING,
value: huks.HuksKeyPadding.HUKS_PADDING_NONE
},
{
tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE,
value: huks.HuksCipherMode.HUKS_MODE_GCM
},
{
// 指定密钥存储的安全等级:首次解锁后可访问
tag: huks.HuksTag.HUKS_TAG_AUTH_STORAGE_LEVEL,
value: huks.HuksAuthStorageLevel.HUKS_AUTH_STORAGE_LEVEL_CE
}
];
let options: huks.HuksOptions = { properties: properties };
// 2. 生成密钥
async function generateKey(): Promise<void> {
await huks.generateKeyItem(keyAlias, options)
.then(() => {
console.info('密钥生成成功');
})
.catch((err: Error) => {
console.error('密钥生成失败: ' + JSON.stringify(err));
});
}
// 3. 使用密钥加密数据
async function encryptData(plainText: Uint8Array): Promise<Uint8Array> {
const encryptOptions: huks.HuksOptions = {
properties: properties,
inData: plainText
};
const result = await huks.initSession(keyAlias, encryptOptions);
const handle = result.handle;
const sessionResult = await huks.updateSession(handle, encryptOptions);
const finishResult = await huks.finishSession(handle, encryptOptions);
return finishResult.outData as Uint8Array;
}
关键要点 :HUKS_TAG_AUTH_STORAGE_LEVEL用于设置密钥的安全等级。HUKS_AUTH_STORAGE_LEVEL_DE表示开机后可访问,HUKS_AUTH_STORAGE_LEVEL_CE表示首次解锁后可访问,HUKS_AUTH_STORAGE_LEVEL_ECE表示解锁状态时可访问。对于登录密码等高敏感数据,应使用CE或ECE级别,确保设备锁屏时密钥不可访问。
1.3 密钥的密文导出与导入
从API version 20开始,HUKS支持以密文形式导出和导入密钥。设置HUKS_TAG_IS_ALLOWED_WRAP为true允许密钥导出,然后调用wrapKeyItem以密文形式导出密钥,调用unwrapKeyItem以密文形式导入密钥。此功能适用于跨设备迁移密钥或备份密钥的场景。
二、网络安全传输
2.1 HTTPS证书链校验机制
当应用通过ArkWeb组件或Network Kit加载HTTPS协议URL时,在TLS握手校验阶段,ArkWeb会调用系统预置的CA根证书,对服务端返回的证书链进行完整性、合法性校验。系统CA证书包含了业界常用的商业CA证书,可以覆盖绝大部分互联网应用和网站的证书链校验需求。
如果校验失败(常见于服务器部署自签名证书的场景),ArkWeb会通过onSslErrorEventReceive和onSslErrorEvent两个回调接口通知应用。
2.2 SSL错误回调的合规处理
正确做法 :在SSL错误回调中,推荐使用系统默认配置(不实现回调),或主动调用handleCancel()取消加载。禁止在回调中调用event.handler.handleConfirm() ,否则会绕过证书校验,导致中间人攻击风险。
typescript
Web({ src: 'https://example.com', controller: this.controller })
.onSslErrorEventReceive((event) => {
// 合规处理:取消加载,而非确认继续
event.handler.handleCancel();
// 可以在此显示自定义错误页面或记录日志
console.error('SSL证书校验失败,已取消加载');
})
2.3 双向认证
对于安全要求更高的场景(如金融、企业应用),建议启用双向认证(Mutual TLS)。客户端不仅验证服务端证书,也提供自身证书进行TLS握手,防止伪冒客户端接入。使用Device Certificate Kit可以进行证书链的合法性校验,其证书管理服务在对数字证书凭据的安装和使用时,依赖Universal Keystore Kit的密钥存储和管理能力。
2.4 Web组件网络通信安全配置
在Web组件的网络通信中,需要注意以下安全配置:
混合内容处理 :将mixedMode配置为MixedMode.None(严格模式),禁止HTTPS页面加载HTTP资源,规避混合内容安全风险。
CSP内容安全策略:在生产环境启用内容安全策略(CSP),并对WebView开启HTTPS强制与证书校验。
域名白名单:只对受信域名白名单页面注入JS或传递敏感信息,仅限同源HTTPS。
三、权限最小化实践
3.1 权限使用原则
HarmonyOS权限使用需满足以下原则:应用(包括应用引用的三方库)所需权限必须在应用的配置文件中严格按照权限开发指导逐个声明;权限申请满足最小化原则,禁止申请非必要的、已废弃的权限;应用申请敏感权限时,必须填写权限使用理由字段;应用敏感权限须在对应业务功能执行前动态申请,满足隐私最小化要求;用户拒绝授予某个权限后,应用与此权限无关的其他业务功能应允许正常使用。
3.2 权限类型与授权方式
HarmonyOS权限分为三种授权方式:
system_grant(系统授权) :应用被允许访问的数据不会涉及到用户或设备的敏感信息。系统会在用户安装应用时自动授予权限。
user_grant(用户授权) :应用被允许访问的数据涉及到用户或设备的敏感信息。需要在安装包中申请权限,还需要在应用动态运行时通过弹窗请求用户授权。
ACL授权:一种特殊的授权方式,用于满足特定场景下的权限需求。
权限等级分为normal(低风险,安装时自动授予)、system_basic(中等风险,部分需要用户授权)、system_core(高风险,仅授予系统应用)。
3.3 动态权限申请的完整流程
权限申请遵循"检查→申请→使用→降级"的标准流程:
typescript
import { abilityAccessCtrl, common, Permissions } from '@kit.AbilityKit';
import { BusinessError } from '@kit.BasicServicesKit';
// 1. 在 module.json5 中声明权限和使用理由
// {
// "requestPermissions": [{
// "name": "ohos.permission.CAMERA",
// "reason": "$string:camera_reason",
// "usedScene": { "abilities": ["EntryAbility"], "when": "inuse" }
// }]
// }
const permissions: Array<Permissions> = ['ohos.permission.CAMERA'];
async function requestCameraPermission(
context: common.UIAbilityContext): Promise<boolean> {
const atManager = abilityAccessCtrl.createAtManager();
try {
// 2. 检查权限状态
const result = await atManager.requestPermissionsFromUser(
context, permissions);
// 3. 根据授权结果决定后续操作
if (result.authResults[0] === 0) {
console.info('相机权限已授权');
return true;
} else {
console.warn('相机权限被拒绝');
// 4. 降级处理:引导用户手动开启或提供替代方案
return false;
}
} catch (err) {
const e = err as BusinessError;
console.error(`权限申请失败: ${e.code}, ${e.message}`);
return false;
}
}
3.4 权限组机制
为减少权限弹窗数量,系统将逻辑紧密相关的user_grant权限组合在一起形成权限组。当应用请求权限时,同一个权限组的权限会在一个弹窗内一起请求用户授权。例如,位置权限组可能包含前台位置和后台位置两个子权限。开发者在申请时应注意权限组的归属关系,合理设计申请时机。
四、隐私合规
4.1 隐私合规高频驳回问题
根据华为应用市场审核数据,隐私合规相关的驳回问题集中在以下八类高频场景:
TOP1:用户同意隐私政策前获取个人信息。所有个人信息获取行为必须在用户同意隐私政策后触发。技术自检时需检查代码日志与调用栈,确保所有个人信息获取行为均在用户同意后触发。
TOP2:权限申请超出必要范围 。遵循权限最小化原则,仅申请业务功能所必要的权限,并在module.json5的requestPermissions标签中声明权限使用场景。
TOP3:隐私标签缺失。如果应用存在收集个人信息的行为,需要勾选填写隐私标签,同时明确使用场景和目的。填写入口在AppGallery Connect > APP与元服务 > 对应应用名称 > 版本信息 > 隐私标签信息录入。
TOP4:隐私政策未以明示同意方式征得同意。征得用户同意的页面不得"默认同意"或"登录即同意",需要增设勾选框并设为默认未勾选状态,由用户主动操作同意。
TOP5:隐私政策不完整。需要以隐私政策弹窗等形式清晰明示处理个人信息的目的、方式和范围,包括静默状态或后台运行时的收集行为。
TOP6:隐私政策开发者信息不一致。隐私政策内的开发者名称及应用名称均需与在AppGallery Connect上提交的信息一致。
4.2 隐私政策与代码行为一致性
审核员会把隐私政策从头到尾读一遍,然后实际操作应用,看收集的数据和隐私政策里写的是否一致。开发者应将代码里所有用到权限、所有调用SDK、所有收集用户数据的地方列一个清单,然后对照这个清单逐条检查隐私政策有没有覆盖。重点检查项包括:应用声明了哪些权限,隐私政策里有没有说明每个权限的用途;第三方SDK有哪些,每个SDK的名称、提供方、收集的数据类型、用途是否写明;有没有收集用户位置、通讯录、相机、麦克风等敏感信息,隐私政策里有没有说明收集目的和使用方式。
4.3 隐私合规开发实践
首次启动隐私弹窗 :应用首次启动时必须弹出隐私政策弹窗,用户同意之前不能采集任何个人信息。module.json5中需要配置隐私政策相关字段,接入的第三方SDK如果有数据采集行为,也要在隐私标签里声明。
敏感权限申请时机:敏感权限必须在运行时动态申请,且申请时机不能过早。应用一启动就弹出一堆权限请求,是审核中常见的驳回原因。应在对应业务功能执行前才申请权限。
日志脱敏:应用运行日志中不应打印用户敏感信息,如手机号、身份证号、密码等。日志脱敏是上架审核的检查项之一。
五、代码保护与加固
5.1 ArkGuard字节码混淆
ArkGuard是HarmonyOS提供的源码混淆工具,支持ArkTS/TS/JS语言,将代码中的函数名、类名、文件名等标识符修改为无意义的短名称,增加逆向工程难度,同时缩小代码体积。
开启混淆的条件 :工程为Stage模型、在Release编译模式下、在模块的build-profile.json5文件中开启混淆配置。从API version 12版本起,默认启用四项推荐的混淆选项:-enable-property-obfuscation(属性名称混淆)、-enable-toplevel-obfuscation(顶层作用域名称混淆)、-enable-filename-obfuscation(文件名混淆)、-enable-export-obfuscation(导入导出名称混淆)。
5.2 混淆配置
在模块的build-profile.json5中配置混淆:
json5
{
"buildOption": {
"arkOptions": {
"obfuscation": {
"ruleOptions": {
"enable": true,
"files": ["./obfuscation-rules.txt"]
}
}
}
}
}
在obfuscation-rules.txt中配置混淆选项:
text
# 开启属性名称混淆
-enable-property-obfuscation
# 开启顶层作用域名称混淆
-enable-toplevel-obfuscation
# 开启文件名混淆
-enable-filename-obfuscation
# 保留需要反射调用的属性名
-keep-property-name
onPageShow
onPageHide
aboutToAppear
# 保留全局名称
-keep-global-name
MyGlobalFunction
5.3 混淆的局限性
ArkGuard提供的是面向方舟字节码的基础名称混淆,不支持高级混淆能力:控制流混淆(如控制流平坦化、虚假分支插入)、数据混淆(如对常量、字面量或内存数据布局做加密与变换)、指令替换或插入无关指令、虚拟机保护/加壳等。
由于ArkGuard仅支持基础混淆能力,开发者不应只依赖ArkGuard来保证应用的安全性。对于源码安全有高要求的开发者,应考虑使用应用加密、第三方安全加固等安全措施来保护代码。多家安全加固厂商已经启动了HarmonyOS开发适配,但由于HarmonyOS代码签名、应用加密等安全机制的限制,以及应用市场上架审核的纯净安全要求,三方加固厂商提供的安全加固内容必须满足相关要求。
5.4 混淆白名单配置
混淆规则写不好,线上直接崩。需要使用-keep-property-name来保留指定的属性名称,使用-keep-global-name保留指定的导出/导入名称,使用-keep-file-name保留文件路径及名称。DevEco Studio提供了混淆助手工具(ObfuscationHelper),可以根据模块和场景对源码进行扫描,快速识别需要配置的保留选项和白名单字段,一键生成白名单混淆规则文件。
六、安全编码最佳实践
6.1 数据安全
应用程序关键数据应该存放在私有目录下,并设置合理的访问权限。应用程序中的敏感个人信息建议加密存储,用于加密的密钥应妥善保存。敏感个人信息包括聊天记录、搜索记录、登录密码等,登录密码等短敏感数据可以使用Asset Store Kit(关键资产存储开发服务)进行存储。
避免将应用私有数据写入公共数据库、存储区中。应用避免将个人数据写入settings数据库。应用程序中用户名密码应使用标准TextInput控件,指定准确的输入类型type(如用户名指定为InputType.USER_NAME,密码指定为InputType.Password等),以支持系统识别关键数据进行安全保护增强。
6.2 通信安全
对跨信任边界传入的参数须进行合法性判断,防止应用异常崩溃。建议使用HTTPS代替HTTP进行通信,并对HTTPS证书进行严格校验。
所有外部输入的数据必须进行严格的校验和过滤,防止SQL注入、XSS等攻击。
6.3 编码安全
涉及外部开源代码或代码漏洞的情况,须关注代码的安全动态和版本更新情况并及时修复。使用官方推荐版本的API接口,不应使用系统废弃的API。代码须通过官方工具的检测,提升代码的可靠性、安全性和代码质量。
建议开启安全编译选项,缓解漏洞带来的潜在风险。建议应用代码通过官方提供的工具进行混淆,防止攻击者针对性的攻击。
七、多元化习题
习题 1(判断题)
题目:在HUKS中生成的密钥,其明文可以在应用主线程中直接读取和使用。
答案:错误
解读:HUKS管理的密钥在全生命周期内,其明文仅在安全环境中进行访问操作,不会将明文传递出安全环境。开发者通过HUKS接口进行加密解密和签名验签操作,但无法直接获取密钥明文。
习题 2(单选题)
题目:以下哪种HUKS密钥安全等级表示密钥在设备首次解锁后才可访问?
A. HUKS_AUTH_STORAGE_LEVEL_DE
B. HUKS_AUTH_STORAGE_LEVEL_CE
C. HUKS_AUTH_STORAGE_LEVEL_ECE
D. HUKS_AUTH_STORAGE_LEVEL_NE
答案:B
解读 :HUKS_AUTH_STORAGE_LEVEL_DE表示开机后可访问,HUKS_AUTH_STORAGE_LEVEL_CE表示首次解锁后可访问,HUKS_AUTH_STORAGE_LEVEL_ECE表示解锁状态时可访问。对于登录密码等高敏感数据,应使用CE或ECE级别。
习题 3(多选题)
题目:关于ArkGuard混淆的局限性,以下说法正确的有(多选):
A. ArkGuard支持控制流混淆
B. ArkGuard不支持数据混淆
C. ArkGuard不支持虚拟机保护/加壳
D. ArkGuard仅支持基础名称混淆
答案:B、C、D
解读:ArkGuard提供的是面向方舟字节码的基础名称混淆,不支持控制流混淆(如控制流平坦化、虚假分支插入)、数据混淆(如对常量、字面量或内存数据布局做加密与变换)、指令替换或插入无关指令、虚拟机保护/加壳等高级混淆能力。
习题 4(代码填空题)
题目:请补全以下代码,在SSL错误回调中合规处理证书校验失败。
typescript
Web({ src: 'https://example.com', controller: this.controller })
.______________((event) => {
// 合规处理:取消加载
event.handler.______________();
})
答案 :onSslErrorEventReceive、handleCancel
解读 :onSslErrorEventReceive是SSL错误回调接口,当证书校验失败时触发。禁止在回调中调用handleConfirm(),应该调用handleCancel()取消加载,避免绕过证书校验导致中间人攻击风险。
习题 5(代码改错题)
题目:以下权限申请代码存在合规问题,请指出并修正。
typescript
@Entry
@Component
struct Index {
aboutToAppear(): void {
// 应用启动时立即申请所有权限
const atManager = abilityAccessCtrl.createAtManager();
const permissions: Array<Permissions> = [
'ohos.permission.CAMERA',
'ohos.permission.MICROPHONE',
'ohos.permission.LOCATION',
'ohos.permission.READ_CONTACTS'
];
atManager.requestPermissionsFromUser(this.getUIContext().getHostContext(), permissions);
}
build() {
Column() {
Text('首页')
}
}
}
答案:该代码在应用启动时就申请了所有权限,违反了"应用敏感权限须在对应业务功能执行前动态申请"的原则。敏感权限申请时机不能过早,应用一启动就弹出一堆权限请求是审核中常见的驳回原因。修正方案是将权限申请移到对应业务功能执行前:
typescript
@Entry
@Component
struct Index {
// 不在 aboutToAppear 中申请权限
build() {
Column({ space: 16 }) {
Text('首页')
// 在需要使用相机时才申请
Button('拍照')
.onClick(async () => {
const context = this.getUIContext().getHostContext();
const granted = await requestCameraPermission(context);
if (granted) {
// 打开相机
}
})
// 在需要使用定位时才申请
Button('获取位置')
.onClick(async () => {
// 申请定位权限
})
}
}
}
解读:敏感权限须在对应业务功能执行前动态申请,满足隐私最小化要求。用户拒绝授予某个权限后,应用与此权限无关的其他业务功能应允许正常使用。
习题 6(简答题)
题目:简述HUKS的核心功能及其三层架构。
答案:HUKS向业务/应用提供各类密钥的统一安全操作能力,核心功能按照密钥生命周期划分包括:密钥生成(随机生成密钥,明文仅在安全环境中访问)、密钥导入(将外部生成的密钥导入HUKS管理)、加密/解密(使用密钥加密或解密数据)、签名/验签(认证消息内容及发送者身份)、密钥协商(两个或多个实体共同建立会话密钥)、密钥封装(通过非对称密钥安全建立共享密钥,支持后量子密码算法)、密钥派生(从一个现有密钥派生新密钥)、访问控制(确保密钥不会被越权访问)、密钥删除(安全删除密钥数据)、密钥证明(为公钥签发证书证明密钥合法性)。三层架构为:SDK层提供密钥管理接口供开发者调用;HUKS服务层实现密钥会话管理及存储管理;HUKS核心层承载密钥的密码学运算、明文密钥的加解密、密钥访问控制等核心功能,必须运行在安全环境内。
解读:HUKS是HarmonyOS安全体系的基石,为应用提供从密钥生成到销毁的全生命周期管理。核心设计理念是密钥明文永不出安全环境,确保即使系统被攻破,密钥也不会泄露。
习题 7(简答题)
题目:简述HarmonyOS应用上架时隐私合规的高频驳回问题及改进建议。
答案:隐私合规高频驳回问题包括八类:用户同意隐私政策前获取个人信息,改进建议是确保所有个人信息获取行为均在用户同意后触发;权限申请超出必要范围,改进建议是遵循权限最小化原则,仅申请业务功能所必要的权限;隐私标签缺失,改进建议是勾选填写隐私标签并明确使用场景和目的;隐私政策未以明示同意方式征得同意,改进建议是增设勾选框并设为默认未勾选状态;隐私政策不完整,改进建议是以隐私政策弹窗等形式清晰明示处理个人信息的目的、方式和范围;隐私政策开发者信息不一致,改进建议是确保隐私政策内的开发者名称及应用名称均与AppGallery Connect上提交的信息一致。
解读:隐私合规是应用上架审核的重灾区。开发者需要将代码里所有用到权限、调用SDK、收集用户数据的地方列一个清单,对照隐私政策逐条检查覆盖情况,确保代码行为与隐私政策描述一致。
八、本节知识点总结
密钥管理与数据加密
Universal Keystore Kit(HUKS)提供密钥全生命周期管理能力,包括密钥生成、导入、加密解密、签名验签、密钥协商、密钥派生等。密钥明文仅在安全环境中访问,不会传递出安全环境。通过HUKS_TAG_AUTH_STORAGE_LEVEL设置密钥安全等级。
网络安全传输
HTTPS证书链校验是保障数据传输安全的核心机制,系统调用预置CA根证书对服务端证书链进行完整性、合法性校验。SSL错误回调中应调用handleCancel()取消加载,禁止调用handleConfirm()。Web组件需配置MixedMode.None严格模式。
权限最小化
权限申请遵循"声明→检查→申请→使用→降级"标准流程。应用敏感权限须在对应业务功能执行前动态申请,用户拒绝后无关功能应正常使用。系统将逻辑紧密相关的权限组合成权限组,减少弹窗数量。
隐私合规
隐私合规高频驳回问题包括用户同意前获取个人信息、权限超出必要范围、隐私标签缺失、隐私政策未明示同意等。隐私政策必须与实际代码行为一致,开发者需将权限、SDK、数据收集行为列清单逐条对照。
代码保护与加固
ArkGuard提供基础名称混淆,支持属性、顶层作用域、文件名、导入导出名称混淆。不支持控制流混淆、数据混淆等高级能力。需通过-keep-property-name等规则配置白名单,避免混淆导致的运行时异常。
安全编码实践
关键数据存放在私有目录并加密存储,敏感个人信息使用Asset Store Kit存储。使用HTTPS代替HTTP并对证书严格校验。对跨信任边界传入的参数进行合法性判断。关注开源代码安全动态并及时修复漏洞。
下节预告
第12课将进入ArkUI的应用架构演进与遗留系统迁移的学习,涵盖从Stage模型到未来架构的演进路径、存量应用迁移策略以及渐进式重构方法论。