Skip to content

安全加固

HarmonyOS 提供多种安全加固手段,保护应用代码和数据安全。


1. 代码混淆

配置混淆规则

json5
// build-profile.json5
{
  "app": {
    "products": [
      {
        "name": "release",
        "buildOption": {
          "arkOptions": {
            "obfuscation": {
              "ruleOptions": {
                "enable": true,
                "consumerRules": [
                  // 保留特定类不混淆
                  '-keep class com.example.model.** { *; }',
                  
                  // 保留接口
                  '-keep interface com.example.api.** { *; }',
                  
                  // 保留枚举
                  '-keep enum com.example.enums.** { *; }',
                  
                  // 保留序列化类
                  '-keep class * implements java.io.Serializable { *; }'
                ]
              }
            }
          }
        }
      }
    ]
  }
}

混淆规则语法

proguard
# 基本语法
-keep [修饰符] 类名 { 成员; }

# 示例
-keep public class com.example.MyClass { *; }           # 保留整个类
-keepclassmembers class * {                              # 保留所有类的特定方法
    public void setName(java.lang.String);
}
-dontwarn com.example.unused.**                          # 忽略警告
-printmapping mapping.txt                                # 输出映射文件

常见保留规则

proguard
# 保留 Model 类(JSON 序列化需要)
-keep class com.example.model.** { *; }

# 保留 API 接口(Retrofit/网络库需要)
-keep interface com.example.api.** { *; }

# 保留注解
-keepattributes *Annotation*

# 保留泛型信息
-keepattributes Signature

# 保留行号(便于调试)
-keepattributes SourceFile,LineNumberTable

2. 反调试保护

检测调试器

typescript
import { process } from '@kit.ArkProcess';

function isDebuggerAttached(): boolean {
  // 检测是否被调试
  let flags = process.getProcessRunningFlags();
  return (flags & process.ProcessFlag.DEBUGGABLE) !== 0;
}

// 定时检测
setInterval(() => {
  if (isDebuggerAttached()) {
    console.warn('检测到调试器,应用将退出');
    // 可选:退出应用或执行其他保护措施
    exitApp();
  }
}, 5000);

防 Hook 检测

typescript
function detectHook(): boolean {
  // 检测常见 Hook 框架特征
  try {
    // Xposed 检测
    let xposedClass = getClassByName('de.robv.android.xposed.XposedBridge');
    if (xposedClass) return true;
    
    // Frida 检测
    let fridaModule = require('frida-gum');
    if (fridaModule) return true;
  } catch {
    return false;
  }
  return false;
}

3. 完整性校验

APK/HAP 完整性校验

typescript
import { cryptoFramework } from '@kit.CryptoArchitectureKit';
import { fileIo } from '@kit.ArkIO';

async function verifyAppIntegrity(): Promise<boolean> {
  // 计算当前 HAP 的哈希值
  let hapPath = getContext().bundleCodeDir;
  let content = await fileIo.readFile(`${hapPath}/entry.hap`);
  
  let digest = await cryptoFramework.createDigest('SHA256');
  let hash = await digest.digest(content);
  
  // 与预存哈希比对
  let expectedHash = getStoredHash();
  return hash === expectedHash;
}

// 启动时校验
aboutToAppear() {
  verifyAppIntegrity().then(valid => {
    if (!valid) {
      console.error('应用完整性校验失败');
      // 限制功能或退出
    }
  });
}

签名校验

typescript
import { bundleManager } from '@kit.ArkKit';

async function verifySignature(): Promise<boolean> {
  let bundleInfo = await bundleManager.getBundleInfoForSelf(
    bundleManager.BundleFlag.GET_BUNDLE_INFO_WITH_CERTIFICATE
  );
  
  let certInfo = bundleInfo.signatureInfo?.certificate;
  if (!certInfo) return false;
  
  // 校验证书指纹
  let fingerprint = calculateFingerprint(certInfo);
  let expectedFingerprint = 'EXPECTED_FINGERPRINT';
  
  return fingerprint === expectedFingerprint;
}

4. 数据加密

敏感数据加密存储

typescript
import { cryptoFramework } from '@kit.CryptoArchitectureKit';

class SecureStorage {
  private encryptor: any;
  
  async init(): Promise<void> {
    this.encryptor = await cryptoFramework.createEncryptor('AES256');
  }
  
  async save(key: string, value: string): Promise<void> {
    let encrypted = await this.encryptor.encrypt(value, {
      keyAlias: 'storage_key'
    });
    await preferences.put(key, encrypted);
  }
  
  async load(key: string): Promise<string | null> {
    let encrypted = preferences.getSync(key) as string;
    if (!encrypted) return null;
    
    try {
      return await this.encryptor.decrypt(encrypted, {
        keyAlias: 'storage_key'
      });
    } catch {
      return null;
    }
  }
}

内存数据保护

typescript
// 敏感数据使用后立即清除
let password = 'sensitive_password';
try {
  // 使用密码
  await authenticate(password);
} finally {
  // 清除内存中的密码
  password = '';  // TypeScript 可能优化掉,需特殊处理
  forceClear(password);
}

function forceClear(str: string): void {
  // 强制覆盖内存
  for (let i = 0; i < str.length; i++) {
    str = str.substring(0, i) + '\0' + str.substring(i + 1);
  }
}

5. Root/越狱检测

检测设备风险

typescript
function isDeviceRooted(): boolean {
  // 检测常见 Root 管理应用
  const rootApps = [
    'com.noshufou.android.su',
    'com.thirdparty.superuser',
    'eu.chainfire.supersu'
  ];
  
  // 检测危险路径
  const dangerousPaths = [
    '/system/bin/su',
    '/system/xbin/su',
    '/sbin/su'
  ];
  
  // 简化检测逻辑
  for (let path of dangerousPaths) {
    if (fileExists(path)) {
      return true;
    }
  }
  
  return false;
}

function fileExists(path: string): boolean {
  try {
    // 尝试访问文件
    return true;
  } catch {
    return false;
  }
}

6. 网络安全加固

SSL Pinning

typescript
import http from '@kit.NetworkKit';

class SecureHttpClient {
  private pinnedCertificates: string[] = [
    'sha256/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA='
  ];
  
  async request(url: string): Promise<string> {
    let httpRequest = http.createHttp();
    
    let response = await httpRequest.request(url, {
      header: {
        'Content-Type': 'application/json'
      },
      extraConfig: {
        // SSL Pinning 配置
        sslVerify: true,
        sslPinnedCertificates: this.pinnedCertificates
      }
    });
    
    return response.result as string;
  }
}

请求签名

typescript
import { cryptoFramework } from '@kit.CryptoArchitectureKit';

async function signRequest(params: Record<string, string>): Promise<string> {
  // 按 key 排序
  let sortedKeys = Object.keys(params).sort();
  let signStr = sortedKeys.map(k => `${k}=${params[k]}`).join('&');
  
  // 添加时间戳和随机数
  let timestamp = Date.now().toString();
  let nonce = Math.random().toString(36).substring(2);
  signStr += `&timestamp=${timestamp}&nonce=${nonce}`;
  
  // HMAC-SHA256 签名
  let hmac = await cryptoFramework.createHmac('SHA256');
  let signature = await hmac.sign(signStr, { keyAlias: 'api_secret' });
  
  return signature;
}

7. 面试高频问题

Q1: 代码混淆的作用是什么?

:代码混淆通过重命名类名、方法名、变量名,删除无用代码,使反编译后的代码难以阅读和理解,增加逆向工程难度。

Q2: 如何实现 SSL Pinning?

:在 HTTP 请求中配置 sslPinnedCertificates,将服务器证书的指纹硬编码在应用中,防止中间人攻击。

Q3: 应用加固有哪些手段?

  1. 代码混淆
  2. 反调试检测
  3. 完整性校验
  4. 数据加密
  5. Root 检测
  6. SSL Pinning
  7. 请求签名

8. 与 Android 对照

概念HarmonyOSAndroid
代码混淆ArkCompiler ObfuscationProGuard/R8
反调试process.getProcessRunningFlagsDebug.isDebuggerConnected
完整性校验SHA256 校验APK Signature Scheme
SSL PinningsslPinnedCertificatesCertificatePinner
Root 检测自定义检测SafetyNet Attestation

面试提示:安全加固是高级开发必备技能,需掌握混淆配置、反调试和完整性校验等核心手段。