针对鸿蒙(HarmonyOS)应用的逆向防护,构建“代码混淆”与“完整性校验”双重防线是保障应用安全的核心。

一、 代码混淆机制(Obfuscation)

代码混淆通过增加代码的复杂性与模糊性,防止他人轻易复制、窃取核心算法,从而大幅提高逆向工程的门槛。

1. 核心防护作用
  • 保护知识产权:防止他人轻易复制和窃取软件代码,保护核心业务逻辑。
  • 防止逆向工程:增加攻击者分析软件工作原理和实现细节的难度,保护应用免受恶意修改或破坏。
  • 提高安全性:减少代码中的漏洞暴露,增加攻击者利用漏洞的难度。
  • 降低反盗版和欺诈风险:增加攻击者破解软件许可验证系统或绕过付费机制的难度。
2. 开启条件与配置

从 DevEco Studio 4.0 Beta1 开始,hvigor 插件提供了代码混淆功能。开启需满足以下条件:

  • 工程为 Stage 模型。
  • 处于 Release 编译模式下(Debug 模式会直接打包源码,不进行混淆)。
  • 在模块的 build-profile.json5 文件中开启混淆配置:
"arkOptions": {
  "obfuscation": {
    "ruleOptions": {
      "enable": true, // 默认为 false,需手动开启
      "files": [
        "./obfuscation-rules.txt"
      ]
    }
  }
}
3. 混淆能力与规则

在 obfuscation-rules.txt 中,开发者可以配置具体的混淆策略。从 DevEco Studio 5.0.3.600 版本起,系统默认启用了四项推荐的混淆选项,以提供更全面的保护:

  • -enable-property-obfuscation:混淆属性名称。
  • -enable-toplevel-obfuscation:混淆全局作用域中的名称。
  • -enable-filename-obfuscation:混淆文件名。
  • -enable-export-obfuscation:混淆导出名称。

二、 完整性校验机制(Integrity Verification)

完整性校验是防止应用被二次打包、篡改代码或注入恶意逻辑的关键屏障。鸿蒙系统在安装和启动应用时,会执行严格的签名与完整性校验流程。

1. 核心校验流程

鸿蒙的签名校验主要分为三个关键步骤:

  • SignatureSchemeBlock 区校验:校验 HAP 包中签名块的证书链完整性。系统会利用内置的根证书,逐级验证中间证书与叶子证书的签名,确保应用来源可信。
  • Profile 校验和解析:验证 Profile 文件的签名,判断其类型,并校验设备的 UDID 是否在允许的安装来源列表内(防止调试包被非法安装到生产环境)。
  • HAP 包完整性校验:计算 HAP 包中所有文件的哈希值,并与签名清单文件(如 .MF 文件)中记录的 SHA-256 哈希进行比对。若发现任何不一致,即判定为内容被篡改,拒绝安装或运行。

2. 应用层增强检测(Device Attestation)

除了系统底层的安装校验,开发者还可以在应用运行时主动调用系统完整性检测接口,进一步防范运行环境风险。检测结果通常以 JWS(JSON Web Signature)格式返回,开发者需在服务端验证其合法性:

  • 解析 JWS 的 Header、Payload 和 Signature,并使用 Root CA 验证证书链。
  • 校验 Payload 中的 hapBundleName 和 hapCertificateSha256,确保应用身份未被伪造。
  • 根据 basicIntegrity 字段判断设备环境。若为 falsedetail 字段会指出具体风险原因,如 jailbreak(越狱)、emulator(模拟器)、attack(设备被攻击)或 unlock(Bootloader 被解锁),应用可据此拒绝提供敏感服务。
1. 应用层防篡改:校验应用签名与完整性

在应用启动时,主动获取自身的签名证书哈希,并与预期的安全哈希值进行比对,防止应用被二次打包或注入恶意代码。

import { bundleManager } from '@kit.AbilityKit';
import { cryptoFramework } from '@kit.CryptoArchitectureKit';

// 场景:启动时校验应用签名,防止被二次打包篡改
async function verifyAppIntegrity(expectedHash: string): Promise<boolean> {
    try {
        // 1. 获取当前应用的证书信息
        const certInfo = await bundleManager.getBundleCertInfo('com.example.myapp');
        const certData = certInfo.certificate; // 获取证书内容
        
        // 2. 计算证书的 SHA-256 哈希值
        const hashAlg = cryptoFramework.createHash('SHA256');
        await hashAlg.update(new cryptoFramework.DataBlob(certData));
        const hashResult = await hashAlg.doFinal();
        
        // 3. 将计算出的哈希转为字符串并与预期值比对
        const currentHash = bufferToHex(hashResult.data);
        if (currentHash !== expectedHash) {
            console.error('应用完整性校验失败:签名被篡改!');
            return false;
        }
        return true;
    } catch (err) {
        console.error('完整性校验异常:', err);
        return false;
    }
}
2. 运行时环境检测:调用 Device Security Kit

利用鸿蒙官方的设备安全服务,检测当前设备是否存在越狱、Root、模拟器或 Bootloader 解锁等高危环境。

import { deviceSecurityKit } from '@kit.DeviceSecurityKit';

// 场景:检测运行环境是否安全
async function checkDeviceEnvironment() {
    try {
        // 调用系统完整性增强检测接口
        const result = await deviceSecurityKit.checkSysIntegrityEnhanced({
            nonce: 'unique-nonce-string' // 传入随机字符串防重放攻击
        });
        
        // 解析返回的 JWS 字符串
        const jwsPayload = parseJWSPayload(result.jwsToken);
        
        if (!jwsPayload.basicIntegrity) {
            console.warn('设备环境存在风险:', jwsPayload.detail);
            // 根据 detail 字段进行针对性处理
            if (jwsPayload.detail.includes('jailbreak')) {
                console.error('设备已越狱,拒绝提供敏感服务');
            } else if (jwsPayload.detail.includes('emulator')) {
                console.error('检测到模拟器运行');
            }
            return false;
        }
        return true;
    } catch (err) {
        console.error('环境检测失败:', err);
        return false;
    }
}
3. 服务端安全校验:验证 JWS 签名与证书链

客户端返回的检测结果必须交由服务端进行严格校验,防止攻击者绕过客户端直接伪造请求。

// 场景:在服务端(Node.js 示例)验证客户端传来的 JWS 凭证
import jwt from 'jsonwebtoken';
import https from 'https';

async function verifyDeviceAttestation(jwsToken: string) {
    try {
        // 1. 解析 JWS 获取 Header 中的证书链 (x5c)
        const decoded = jwt.decode(jwsToken, { complete: true });
        const certChain = decoded.header.x5c;
        
        // 2. 验证证书链:使用 Root CA 验证证书链的合法性
        // 校验 x5c[0] 的 CN 是否为 'Harmony OS Device Attestation Service'
        const isValidCertChain = await validateCertChain(certChain);
        if (!isValidCertChain) {
            throw new Error('证书链验证失败,凭证可能被伪造');
        }
        
        // 3. 使用证书链中的公钥验证 JWS 签名
        const payload = jwt.verify(jwsToken, certChain[0], { algorithms: ['ES256'] });
        
        // 4. 校验业务字段
        if (payload.hapBundleName !== 'com.example.myapp') {
            throw new Error('应用包名不匹配');
        }
        
        console.info('设备环境校验通过,安全等级:', payload.basicIntegrity);
        return payload;
    } catch (err) {
        console.error('服务端 JWS 校验失败:', err);
        return null;
    }
}

三、 应用加密与分发级防护

除了开发阶段的混淆,鸿蒙系统还在分发和运行阶段提供了系统级的代码保护机制,防止静态分析。

  1. 应用市场端到端加密:开发者在上架应用时可选择开启加密。经过应用市场审核与加密后的安装包,在设备上安装落盘后仍处于受保护状态。应用启动时,系统会逐页按需解密,解密内容仅存在于内存中,不会写入磁盘,从而有效防止攻击者通过静态分析逆向破解应用代码结构。
  2. 强制代码签名与热更新防护:为防止恶意应用绕过审核,鸿蒙引入了强制代码签名机制。不仅在加载时进行合法性检查,还在应用代码执行前通过哈希校验验证内容的完整性,有效拦截通过热更新机制加载未审核代码的风险。
1. 上架阶段:开启应用市场端到端加密

应用加密特性在应用上架时配置,对开发者透明且无需修改业务代码。应用包在应用市场审核通过后会被加密,安装落盘后仍受保护,启动时由系统内核按需解密执行。

// 场景:在 AppGallery Connect 后台发布应用时的配置步骤
// 1. 登录 AppGallery Connect,进入应用的发布页面。
// 2. 在“选取待发布的软件包”步骤中,勾选“应用加密”选项。
// 3. 提交审核。审核通过后,应用市场会对包体中的关键资产(如 .abc 文件)进行端到端加密。

// 注意事项:
// - 加密后的应用在启动和运行过程中可能会有轻微的性能开销,包体大小也会略微增加。
// - 当前 ArkTS 卡片服务对应的 widgets.abc 文件暂不支持加密服务。
// - 由于应用加密特性对应用冷启动时延有影响,目前部分版本通过白名单方式受限开放,需提前申请。
2. 运行时防护:应用完整性自校验

为了防止应用被二次打包、篡改或注入恶意逻辑,开发者可以在应用启动时主动校验自身 HAP 包的完整性。

import { bundleManager } from '@kit.AbilityKit';
import { cryptoFramework } from '@kit.CryptoArchitectureKit';

// 场景:应用启动时校验自身完整性,防止被二次打包篡改
async function verifyAppIntegrity(expectedHapHash: string): Promise<boolean> {
    try {
        // 1. 获取当前应用的 HAP 包信息
        const bundleInfo = await bundleManager.getBundleInfoForSelf(
            bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_HAP
        );
        
        // 2. 计算当前 HAP 包的 SHA-256 哈希值
        // 注意:此处为伪代码逻辑,实际需读取 HAP 文件流进行哈希计算
        const hashAlg = cryptoFramework.createHash('SHA256');
        // await hashAlg.update(hapFileData); 
        const hashResult = await hashAlg.doFinal();
        
        // 3. 将计算出的哈希转为字符串并与预期值比对
        const currentHash = bufferToHex(hashResult.data);
        if (currentHash !== expectedHapHash) {
            console.error('应用完整性校验失败:应用可能被篡改或二次打包!');
            return false;
        }
        return true;
    } catch (err) {
        console.error('完整性校验异常:', err);
        return false;
    }
}
3. 运行时防护:防动态调试与热更新拦截

为防止攻击者通过动态调试或热更新机制加载未审核代码,需在运行时进行环境检测与内存保护。

import { process } from '@kit.ArkTS';
import { Debug } from '@kit.ArkTS';

// 场景:运行时防调试与防篡改检测
class AppSecurityGuard {
    private static readonly CHECK_INTERVAL = 5000; // 每5秒检测一次

    public static startMonitoring() {
        setInterval(() => {
            // 1. 检测是否被动态调试器附加
            if (Debug.isAttached() || process.isDebugged()) {
                console.error('检测到非法调试环境,应用即将退出');
                AppSecurityGuard.secureWipeAndExit();
            }
            
            // 2. 可在此处增加 HAP 包哈希的定期校验
            // 防止应用运行期间被内存注入或热更新篡改
        }, AppSecurityGuard.CHECK_INTERVAL);
    }

    private static secureWipeAndExit() {
        // 敏感数据内存擦除,防止内存转储泄露
        // 实际场景中需对内存中的 Token、密钥等进行覆写清零
        console.warn('正在执行安全擦除...');
        process.exit(1); // 强制退出应用
    }
}

四、 进阶代码混淆策略(控制流与数据混淆)

基础混淆仅重命名符号,高级攻击者仍可通过逻辑分析还原代码。针对高价值应用,需引入更深层的混淆技术:

  1. 控制流混淆(逻辑迷宫):将原本清晰的直线代码逻辑改造为复杂的结构。例如,插入“不透明谓词”和“虚假控制流”(如永远不会执行的代码块或假循环),并将真实逻辑拆分成多个基本块,通过复杂的跳转关系连接。这能极大延长逆向分析时间。
  2. 数据与字符串混淆(隐身术):明文字符串(如 API Key)极易被提取。通过数据混淆,将敏感字符串在编译时转化为加密的字节序列,仅在运行时首次访问时调用解密函数,且进程退出后自动清除内存。同时,对关键常量使用数学运算(如异或、加减法组合)进行等价替换,提升常量提取难度。

五、 核心资产的精细化访问控制

在防逆向的基础上,鸿蒙对应用运行时读取敏感数据(关键资产)实施了基于上下文的访问控制策略,即使设备被攻破也能限制数据泄露范围:

  1. 基于锁屏与认证状态的访问控制
    • 首次解锁后可访问:适用于普通社交应用,设备未解锁时关键资产不可访问,平衡了安全与便利。
    • 解锁后可访问:适用于金融、银行类应用。只有在设备处于解锁状态且用户通过身份验证(如指纹、面容、PIN码)后才能访问。若设备丢失且未解锁,攻击者无法获取交易明细等核心数据。
    • 基于锁屏密码设置状态:若设备未设置锁屏密码,应用可直接拒绝访问关键资产,防止设备在无基础保护时被轻易窃取数据。
  2. 基于所有权的严格隔离:每个关键资产都关联特定的所有者(应用)。不同应用之间的数据严格受限,即使社交应用被恶意攻击,攻击者也无法跨越沙箱获取银行应用中的用户登录凭据。
1. 基础访问控制:基于锁屏状态的策略

在存储敏感数据时,可通过设置 ACCESSIBILITY 属性来限制数据在何种锁屏状态下可被访问。

import { asset } from '@kit.AssetStoreKit';
import { util } from '@kit.ArkTS';

// 场景:存储普通社交应用的 Token,设置“首次解锁后可访问”
async function saveSocialToken(token: string) {
    let attr: asset.AssetMap = new Map();
    attr.set(asset.Tag.SECRET, new util.TextEncoder().encodeInto(token));
    attr.set(asset.Tag.ALIAS, new util.TextEncoder().encodeInto('social_token'));
    
    // 【关键】设置访问控制:设备首次解锁后即可访问,未解锁时不可读取
    attr.set(asset.Tag.ACCESSIBILITY, asset.Accessibility.DEVICE_FIRST_UNLOCKED);
    
    try {
        await asset.add(attr);
        console.info('社交 Token 存储成功,受锁屏状态保护');
    } catch (err) {
        console.error('存储失败:', err);
    }
}
2. 高级访问控制:结合用户认证(指纹/人脸/PIN)

对于金融级核心资产,必须结合用户生物识别或 PIN 码认证,并设置认证有效期,实现“一次认证,多次访问”。

import { asset } from '@kit.AssetStoreKit';
import { userAuth } from '@kit.UserAuthKit';
import { util } from '@kit.ArkTS';

// 场景:存储银行卡号,要求必须通过指纹或PIN码认证,且认证有效期为 300 秒
async function saveBankCard(cardNumber: string) {
    let attr: asset.AssetMap = new Map();
    attr.set(asset.Tag.SECRET, new util.TextEncoder().encodeInto(cardNumber));
    attr.set(asset.Tag.ALIAS, new util.TextEncoder().encodeInto('bank_card'));
    
    // 【关键】设置认证类型:支持指纹或 PIN 码
    attr.set(asset.Tag.AUTH_TYPE, userAuth.UserAuthType.FINGERPRINT | userAuth.UserAuthType.PIN);
    // 【关键】设置认证有效期:300秒内再次访问无需重复认证
    attr.set(asset.Tag.AUTH_VALIDITY_PERIOD, 300);
    
    try {
        await asset.add(attr);
        console.info('银行卡号存储成功,已绑定强认证策略');
    } catch (err) {
        console.error('存储失败:', err);
    }
}

// 场景:读取银行卡号(需经历 挑战值生成 -> 用户认证 -> 携带令牌查询 三步)
async function queryBankCard() {
    let alias = new util.TextEncoder().encodeInto('bank_card');
    
    // 1. 预处理:获取系统生成的挑战值 (Challenge)
    let preQueryMap: asset.AssetMap = new Map();
    preQueryMap.set(asset.Tag.ALIAS, alias);
    preQueryMap.set(asset.Tag.AUTH_TYPE, userAuth.UserAuthType.FINGERPRINT | userAuth.UserAuthType.PIN);
    
    const challenge = await asset.preQuery(preQueryMap);
    
    // 2. 拉起系统认证框,获取认证令牌 (Auth Token)
    const authParam: userAuth.AuthParam = {
        challenge: challenge,
        authType: [userAuth.UserAuthType.FINGERPRINT, userAuth.UserAuthType.PIN],
        authTrustLevel: userAuth.AuthTrustLevel.ATL1,
    };
    const widgetParam: userAuth.WidgetParam = { title: '请验证身份以查看银行卡号' };
    
    const userAuthInstance = userAuth.getUserAuthInstance(authParam, widgetParam);
    userAuthInstance.on('result', async (result) => {
        if (result.result === 12500000) { // 认证成功
            // 3. 携带 Challenge 和 Token 查询真实数据
            let queryMap: asset.AssetMap = new Map();
            queryMap.set(asset.Tag.ALIAS, alias);
            queryMap.set(asset.Tag.AUTH_CHALLENGE, challenge);
            queryMap.set(asset.Tag.AUTH_TOKEN, result.token);
            queryMap.set(asset.Tag.RETURN_TYPE, asset.ReturnType.ALL);
            
            const assets = await asset.query(queryMap);
            console.info('成功获取银行卡号:', new util.TextDecoder().decodeWithStream(assets[0].get(asset.Tag.SECRET)));
            
            // 4. 清除挑战值(必须执行,否则后续查询会报错)
            let postMap: asset.AssetMap = new Map();
            postMap.set(asset.Tag.AUTH_CHALLENGE, challenge);
            await asset.postQuery(postMap);
        }
    });
    userAuthInstance.start();
}
3. 跨应用数据共享:基于群组的访问控制

在鸿蒙生态中,同一开发者开发的多个应用(如主应用与手表端应用)可以通过配置群组来安全地共享核心资产。

import { asset } from '@kit.AssetStoreKit';
import { util } from '@kit.ArkTS';

// 场景:将用户登录凭证存入群组,允许同开发者的其他应用读取
async function saveSharedCredential(credential: string) {
    let attr: asset.AssetMap = new Map();
    attr.set(asset.Tag.SECRET, new util.TextEncoder().encodeInto(credential));
    attr.set(asset.Tag.ALIAS, new util.TextEncoder().encodeInto('user_credential'));
    
    // 【关键】开启群组共享(需在 module.json5 中提前配置好 groupId)
    // 注意:IS_PERSISTENT 为 true 的资产不允许设置为群组共享
    attr.set(asset.Tag.IS_SHARED, true); 
    
    try {
        await asset.add(attr);
        console.info('凭证已存入群组,同生态应用可安全读取');
    } catch (err) {
        console.error('群组存储失败:', err);
    }
}

六、 运行时环境检测(Safety Detect)

在应用运行过程中,需主动探测设备的运行环境是否可信,以阻断高危操作:

  1. 系统完整性检测(SysIntegrity):利用设备上的可信执行环境(TEE),检查用户设备是否被 Root、Bootloader 是否被解锁或权限是否被提升。若检测到异常,应用应限制在线支付等敏感操作。
  2. 应用与用户行为检测:通过 AppsCheck 获取设备上的恶意应用列表以评估风险;通过 UserDetect 识别虚假用户(如利用验证码防止批量注册和爬虫),防止接口被恶意滥用。

七、 数据完整性与防篡改保护

在数据的存储和传输过程中,除了加密,还必须确保数据未被篡改:

  1. 哈希校验机制:系统采用哈希算法将关键资产转换为固定长度的哈希值并一同存储。读取时重新计算并比对,若不一致则说明数据已损坏或被篡改,系统将拒绝使用该数据。
  2. 应用层完整性自校验:在应用启动时,主动计算自身 HAP 包的 SHA256 哈希值,并与预期的硬编码哈希值进行比对。若发现被篡改(如二次打包),直接退出应用以防止恶意逻辑执行。
Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐