Appearance
安全加固
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,LineNumberTable2. 反调试保护
检测调试器
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 += `×tamp=${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: 应用加固有哪些手段?
答:
- 代码混淆
- 反调试检测
- 完整性校验
- 数据加密
- Root 检测
- SSL Pinning
- 请求签名
8. 与 Android 对照
| 概念 | HarmonyOS | Android |
|---|---|---|
| 代码混淆 | ArkCompiler Obfuscation | ProGuard/R8 |
| 反调试 | process.getProcessRunningFlags | Debug.isDebuggerConnected |
| 完整性校验 | SHA256 校验 | APK Signature Scheme |
| SSL Pinning | sslPinnedCertificates | CertificatePinner |
| Root 检测 | 自定义检测 | SafetyNet Attestation |
面试提示:安全加固是高级开发必备技能,需掌握混淆配置、反调试和完整性校验等核心手段。