在金融级应用的交付前夕,安全团队在渗透测试中给出了一封红色警告:本地数据库中的用户身份凭据存在明文泄露风险。早期的我们只是简单地在 ArkTS 层用了一个硬编码的 AES 密码进行加密。这在黑客眼里,等同于把钥匙插在门上。这次重构迫使我们全面迁入系统级的 HUKS(通用密钥库系统),过程可谓脱胎换骨。
抛弃软加密的死胡同
硬编码密钥的隐患在于,HAP 包一旦被反编译,或者应用运行内存被 Dump,密钥就一览无余。HUKS 的核心在于利用硬件级的安全环境(TEE),让密钥的生成、存储和运算全在芯片内部完成。你的应用只能拿到一个"别名(Alias)"去请求系统代为运算,密钥明文永远不会暴露在应用沙箱里。
复杂的密钥属性配置
第一次对接 HUKS 接口时,很容易被那一长串的 HuksParam 配置搞晕。这里面的每一项都关乎你的加密强度。
typescript
import huks from '@ohos.security.huks';
const KEY_ALIAS = 'finance_vault_key';
const properties: 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 },
// 警示:金融级安全必须使用 GCM 模式,它自带数据完整性校验
{ tag: huks.HuksTag.HUKS_TAG_BLOCK_MODE, value: huks.HuksCipherMode.HUKS_MODE_GCM },
{ tag: huks.HuksTag.HUKS_TAG_PADDING, value: huks.HuksKeyPadding.HUKS_PADDING_NONE }
];
调用 huks.generateKeyItem 后,系统底层就会在安全区里生成一个 256 位的 AES 密钥。注意,此时你的应用里完全没有这个密钥的影子。
GCM 模式下的 IV 陷阱
在加密数据时,GCM 模式要求必须传入一个随机生成的 IV(初始化向量)。如果你用了固定的 IV,或者干脆不传,系统会直接抛出参数错误异常。
很多开发者在加密成功后,把密文存进数据库,却把 IV 给丢了,导致解密时死活解不开。警示: IV 的长度通常是 12 字节,由于 HUKS 不支持将 IV 与密文自动绑定,你必须手动将生成的随机 IV 拼接到密文的前面,一起存入数据库。解密时,再切出前 12 个字节作为 IV 传入。
typescript
// 解密时的正确姿势
const combined = new Uint8Array(base64DecodedData);
const iv = combined.slice(0, 12); // 切出IV
const cipherData = combined.slice(12); // 剩下的才是真密文
// 再将 iv 和 cipherData 传入 huks 进行解密
数据库与偏好存储的加密联动
仅仅加密几个字段是不够的。黑客如果把整个数据库文件拷走,依然能做很多坏事。在初始化 relationalStore 时,必须开启数据库级别的加密。
typescript
const storeConfig: relationalStore.StoreConfig = {
name: 'finance.db',
securityLevel: relationalStore.SecurityLevel.S3, // 高安全级别
encrypt: true // 开启数据库文件加密,底层由系统接管
};
同时,对于 Preferences,千万不要直接存敏感数据。先把对象序列化为 JSON 字符串,用 HUKS 加密后,再存进去。虽然这会增加一点读写耗时,但在安全面前,这点性能损耗微不足道。
跨设备流转的密钥断崖
在测试"应用接续"和"换机克隆"时,我们发现了一个致命问题。HUKS 的密钥是强绑定在当前物理设备上的。当用户把数据迁移到新手机时,旧的加密数据库文件也被搬过去了,但新手机的安全环境里没有对应的密钥,导致数据全部变成乱码,应用直接死机。
解决方案: 必须在 BackupExtensionAbility 中,将本地的加密数据库从备份白名单中剔除。并设计一套云端同步的方案,让用户在新设备上重新登录后,从云端拉取解密后的数据,再用新设备的 HUKS 密钥重新加密落盘。绝不能指望硬件密钥能够跨设备流浪。
写一个完整的加密解密工具类。生成一段 JSON 文本,用 HUKS 加密为 Base64 字符串存入 RDB。重启应用后,从 RDB 取出密文并解密。验证结果是否与原文完全一致。如果在解密时抛出异常,优先检查你的 IV 提取逻辑是否正确。