HarmonyOS 6.1 安全攻防实战:从“裸奔”到“防弹”的代码级防护
系列安全加固篇·第48篇。AI融合篇后有安全专家问“Demo功能这么全但代码有没有被反编译的风险用户数据会不会被中间人劫持界面会不会被恶意APP覆盖钓鱼” 安全是应用的底线。今天我们将电商Demo进行一次彻底的安全“体检”和“加固”覆盖代码混淆、防逆向、数据加密、防界面劫持、证书锁定、Root检测等关键领域。我们将使用DevEco Studio安全插件和华为安全检测服务模拟黑客攻击并修复漏洞。全程基于API23含官方文档未涉及的“Native层防护”和“运行时自检”技巧。一、前言为什么“功能完整”不等于“可以上线”很多开发者认为“只要功能跑通了加个HTTPS就是安全”。现实是残酷的静态分析黑客用jadx反编译你的HAP包秒读你的API Key和加密逻辑。动态调试用fridahook你的登录函数绕过密码验证。中间人攻击用Charles抓包看光你的所有网络请求。界面劫持恶意APP覆盖你的支付界面诱导用户输入密码。安全原则永远不要相信客户端环境。今天的实战我们将假设客户端运行在“敌占区”通过层层防御即使代码被反编译数据被拦截也能将损失降到最低。二、核心概念辨析常见安全误区误区真相正确做法HTTPS安全HTTPS只加密传输不防客户端破解代码混淆数据二次加密前端验证安全前端验证可被绕过关键逻辑必须后端验证硬编码密钥方便硬编码密钥等于没加密使用KeyStore/Enclave存储日志调试高效日志可能泄露敏感信息发布版移除所有调试日志权限越多功能越强过多权限增加攻击面最小权限原则三、代码实现从“裸奔”到“防弹”3.1 代码混淆与字符串加密防止反编译后直接看到明文逻辑。步骤1开启混淆在build-profile.json5中配置{ buildOption: { arkOptions: { obfuscation: { enable: true, // 开启混淆 rules: ./obfuscation-rules.txt // 混淆规则文件 } } } }步骤2编写混淆规则 (obfuscation-rules.txt)# 保留ArkUI组件否则界面会白屏 -keep class * extends ohos.arkui.UIComponent { *; } -keep class * extends ohos.arkui.Component { *; } # 保留Entry注解的类 -keep ohos.arkui.annotation.Entry class * { *; } # 保留Native方法 -keepclasseswithmembernames class * { native methods; } # 混淆所有本地变量名和方法名 -obfuscate_names -obfuscate_methods -obfuscate_fields # 移除日志关键 -assumenosideeffects class ohos.hiviewdfx.HiLog { public static *** d(...); public static *** i(...); public static *** w(...); }步骤3字符串加密自定义脚本创建scripts/encrypt_strings.js在构建前加密敏感字符串// 简单的异或加密示例 const crypto require(crypto); function xorEncrypt(text, key) { let result ; for (let i 0; i text.length; i) { result String.fromCharCode(text.charCodeAt(i) ^ key.charCodeAt(i % key.length)); } return Buffer.from(result).toString(base64); } // 加密API Key const apiKey your_real_api_key_here; const encryptedKey xorEncrypt(apiKey, secret_key); console.log(Encrypted API Key: ${encryptedKey}); // 在ETS代码中使用解密函数 // const decryptedKey xorDecrypt(encryptedKey, secret_key);3.2 数据安全多层加密与KeyStore错误示范// 明文存储密码 preferences.putSync(password, 123456);正确做法import { cryptoFramework } from kit.CryptoArchitectureKit import { huks } from kit.UniversalKeyStoreKit export class SecureStorage { private static readonly KEY_ALIAS user_password_key private static readonly TRANSFORMATION AES/GCM/NoPadding /** * 生成并存储AES密钥到HUKS硬件安全环境 */ async generateAndStoreKey(): Promisevoid { const keyProperties { alg: huks.HuksKeyAlg.HUKS_ALG_AES, size: huks.HuksKeySize.HUKS_AES_KEY_SIZE_256, purpose: huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_ENCRYPT | huks.HuksKeyPurpose.HUKS_KEY_PURPOSE_DECRYPT, digest: huks.HuksKeyDigest.HUKS_DIGEST_SHA256, padding: huks.HuksKeyPadding.HUKS_PADDING_NONE, blockMode: huks.HuksKeyMode.HUKS_MODE_GCM } const options { properties: [keyProperties] } try { await huks.generateKey(SecureStorage.KEY_ALIAS, options) console.log(密钥已安全存储在HUKS中) } catch (err) { console.error(密钥生成失败:, err) } } /** * 加密数据 */ async encrypt(data: string): Promisestring { const cipher cryptoFramework.createCipher(SecureStorage.TRANSFORMATION) const key await this.getKey() const iv cryptoFramework.createRandomIv(12) // GCM模式需要12字节IV await cipher.init(cryptoFramework.CryptoMode.ENCRYPT_MODE, key, iv) const inputData { data: new Uint8Array(new TextEncoder().encode(data)) } const encryptedData await cipher.doFinal(inputData) // 将IV和密文一起存储 const result new Uint8Array(iv.data.length encryptedData.data.length) result.set(iv.data, 0) result.set(encryptedData.data, iv.data.length) return Buffer.from(result).toString(base64) } /** * 解密数据 */ async decrypt(base64Data: string): Promisestring { const data Buffer.from(base64Data, base64) const iv data.slice(0, 12) const encrypted data.slice(12) const cipher cryptoFramework.createCipher(SecureStorage.TRANSFORMATION) const key await this.getKey() const ivParam { data: new Uint8Array(iv) } await cipher.init(cryptoFramework.CryptoMode.DECRYPT_MODE, key, ivParam) const encryptedParam { data: new Uint8Array(encrypted) } const decryptedData await cipher.doFinal(encryptedParam) return new TextDecoder().decode(decryptedData.data) } /** * 从HUKS获取密钥 */ private async getKey(): PromisecryptoFramework.SymKey { const keyBlob await huks.getKey(SecureStorage.KEY_ALIAS, { properties: [] }) return cryptoFramework.convertKey(keyBlob) } }3.3 网络安全证书锁定与双向认证防止中间人攻击MitM。步骤1证书锁定Certificate Pinning在module.json5中配置{ module: { metadata: [ { name: network-security-config, resource: $profile:network_security_config } ] } }创建resources/base/profile/network_security_config.xml?xml version1.0 encodingutf-8? network-security-config domain-config cleartextTrafficPermittedfalse domain includeSubdomainstrueapi.yourdomain.com/domain pin-set expiration2024-12-31 !-- 你的域名证书公钥哈希Base64编码 -- pin digestSHA-256AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA/pin !-- 备份证书公钥哈希 -- pin digestSHA-256BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB/pin /pin-set !-- 强制使用证书锁定 -- trust-anchors certificates srcraw/your_certificate/ /trust-anchors /domain-config /network-security-config步骤2双向SSL认证import { http } from kit.NetworkKit import { cryptoCert } from kit.CryptoArchitectureKit async function secureRequest(): Promisevoid { const httpRequest http.createHttp() // 加载客户端证书P12文件 const clientCert await fileIo.readFile(getContext().filesDir /client.p12) const certBlob: cryptoCert.EncodingBlob { data: new Uint8Array(clientCert), encoding: cryptoCert.EncodingFormat.FORMAT_PKCS12 } // 配置双向认证 const options: http.HttpRequestOptions { method: http.RequestMethod.POST, header: { Content-Type: application/json }, caCert: -----BEGIN CERTIFICATE-----\n...服务器证书...\n-----END CERTIFICATE-----, clientCert: certBlob, clientCertPassword: cert_password, // 证书密码 sslVerifyMode: http.SslVerifyMode.VERIFY_PEER | http.SslVerifyMode.VERIFY_HOSTNAME } try { const response await httpRequest.request(https://api.yourdomain.com/secure-endpoint, options) console.log(安全请求成功:, response.result) } catch (err) { console.error(安全请求失败:, err) // 证书验证失败可能是中间人攻击 promptAction.showToast({ message: 网络连接不安全请检查网络环境 }) } }3.4 运行时防护防调试、防Root、防注入检测调试器import { hidebug } from kit.PerformanceAnalysisKit export class RuntimeProtection { /** * 检测是否被调试 */ static isBeingDebugged(): boolean { try { // hidebug.isDebuggerConnected() 返回是否连接调试器 return hidebug.isDebuggerConnected() } catch (err) { console.error(检测调试器失败:, err) return false } } /** * 检测设备是否已Root/Jailbreak */ static isDeviceRooted(): Promiseboolean { return new Promise((resolve) { // 检查常见Root路径 const rootPaths [ /system/bin/su, /system/xbin/su, /sbin/su, /vendor/bin/su, /system/app/Superuser.apk ] let foundRoot false rootPaths.forEach(path { try { fileIo.accessSync(path) foundRoot true } catch (e) { // 文件不存在 } }) // 检查是否可以写入系统目录 try { const testFile /system/test_rooted fileIo.writeSync(fileIo.openSync(testFile, fileIo.OpenMode.WRITE_ONLY), new Uint8Array([1])) fileIo.unlinkSync(testFile) foundRoot true } catch (e) { // 无法写入 } resolve(foundRoot) }) } /** * 检测是否被Frida等工具注入 */ static isInjected(): boolean { // 检查/proc/self/maps中是否存在frida相关模块 try { const maps fileIo.readTextSync(/proc/self/maps) if (maps.includes(frida) || maps.includes(gadget)) { return true } } catch (err) { // 无法读取maps文件 } return false } /** * 运行时自检 */ static async selfCheck(): Promiseboolean { console.log(开始运行时自检...) if (this.isBeingDebugged()) { console.error(检测到调试器连接) return false } if (await this.isDeviceRooted()) { console.warn(设备已Root安全性降低) // 可以选择降低功能级别而非直接退出 } if (this.isInjected()) { console.error(检测到代码注入) return false } console.log(运行时自检通过) return true } }3.5 防界面劫持Overlay Attackimport { window } from kit.ArkUI import { abilityAccessCtrl } from kit.AbilityKit Entry Component struct SecurePaymentPage { private windowClass: window.Window | null null aboutToAppear(): void { this.protectAgainstOverlay() } /** * 防止界面被覆盖 */ async protectAgainstOverlay(): Promisevoid { try { // 1. 获取窗口实例 this.windowClass await window.getLastWindow(getContext(this)) // 2. 设置窗口属性防止被其他应用覆盖 // 注意HarmonyOS没有直接等同于Android SYSTEM_ALERT_WINDOW的权限 // 但可以通过以下方式增强安全性 // 设置窗口为全屏减少被覆盖的可能性 this.windowClass.setWindowLayoutFullScreen(true) // 设置窗口焦点变化监听 this.windowClass.on(windowEvent, (data) { if (data window.WindowEventType.WINDOW_EVENT_FOCUS_OUT) { // 窗口失去焦点可能被其他应用覆盖 this.onWindowFocusLost() } }) // 3. 检查悬浮窗权限如果应用使用了悬浮窗 const atManager abilityAccessCtrl.createAtManager() const result await atManager.checkAccessToken( abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED, ohos.permission.SYSTEM_FLOAT_WINDOW ) if (result ! abilityAccessCtrl.GrantStatus.PERMISSION_GRANTED) { console.log(未授予悬浮窗权限降低被覆盖风险) } } catch (err) { console.error(防覆盖设置失败:, err) } } onWindowFocusLost(): void { // 窗口失去焦点时的处理逻辑 console.warn(支付页面失去焦点可能存在安全风险) promptAction.showToast({ message: 警告页面失去焦点请确认环境安全 }) // 可以选择暂时模糊页面内容 this.blurContent() } blurContent(): void { // 实现页面模糊效果 console.log(模糊页面内容以保护隐私) } build() { Column() { Text(安全支付页面) .fontSize(24) .margin(20) Text(请确认当前页面为官方应用警惕仿冒界面) .fontSize(14) .fontColor(#FF0000) .margin(10) // ... 支付表单 } .width(100%) .height(100%) .backgroundColor(#FFFFFF) } }四、踩坑记录官方文档没写的安全细节混淆导致的“灵异bug”混淆后ArkUI的State变量名可能被改变导致UI不更新。解决方案在混淆规则中保留所有State、Prop、Link等装饰器修饰的变量-keepclassmembers class * { ohos.arkui.State *; }。HUKS的性能陷阱每次加密解密都从HUKS获取密钥会有性能开销。解决方案在应用启动时获取一次密钥缓存在内存中注意内存清理或使用密钥派生函数KDF从主密钥派生会话密钥。证书锁定的维护噩梦证书过期或更换会导致应用无法联网。解决方案在pin-set中配置备份证书实现证书轮换机制在旧证书过期前通过云端下发新证书指纹。Root检测的误报某些安全软件或系统更新可能导致Root检测误报。解决方案不要仅依赖单一检测方法结合多种检测手段检测到Root时采取降级处理如禁用敏感功能而非直接崩溃。Native层防护的必要性JS代码容易被反编译核心安全逻辑如签名验证、密钥派生应放在Native层C/C实现并通过NAPI调用。虽然Native代码也能被逆向但难度呈指数级上升。

相关新闻

ASE复刻《原神》风格草地:从Shader原理到性能优化全解析

ASE复刻《原神》风格草地:从Shader原理到性能优化全解析

1. 项目概述:为什么选择ASE复刻《原神》风格草地? 如果你在Unity里做过场景,尤其是开放世界或者风格化渲染,肯定对《原神》里那片随风摇曳、色彩层次丰富的草地印象深刻。那种草地的灵动感,远不是贴一张草皮纹理就能搞…

2026/10/5 14:29:11 阅读更多 →
HarmonyOS 6.1 AI深度融合:从“功能”到“智能”的大模型落地

HarmonyOS 6.1 AI深度融合:从“功能”到“智能”的大模型落地

系列智能化篇第47篇。全场景篇后,有产品经理问:“现在的电商Demo功能齐全了,但感觉还是‘死’的。能不能接入AI,让它像真人客服一样聊天,或者自动生成商品文案?” 这正是生成式AI(GenAI&#xf…

2026/10/4 1:58:37 阅读更多 →
18650电池片定制实力企业

18650电池片定制实力企业

找18650电池片定制,为何实力企业是品质的“压舱石”?在新能源浪潮席卷全球的今天,18650电池片作为动力与储能的基石,其定制化需求正变得前所未有的旺盛。从智能小家电到电动工具,从便携式储能到精密仪器,一…

2026/10/4 15:39:00 阅读更多 →

最新新闻

Codeforces Round 1078

Codeforces Round 1078

【codeforces赛时录屏】Codeforces Round 1078 (Div. 2) https://www.bilibili.com/video/BV1C1FfzdEiC/ Codeforces Round 1078 (Div. 2) 赛时4题(A-D) https://www.bilibili.com/video/BV11mcczAEBT/ Codeforces上分攻略1: 计划 https://www.bilibili.com/video/BV1tK42117h4…

2026/10/5 14:29:57 阅读更多 →
TokenGT:图Transformer的机制可解释性新范式

TokenGT:图Transformer的机制可解释性新范式

1. 这不是又一篇“可视化热力图”论文:TokenGT 的机制可解释性到底在解什么题?ICML2026 上 LG AI Research 发布的 TokenGT,标题里带“机制可解释性”四个字,但如果你点开论文第一眼就去找 Grad-CAM、Attention Rollout 或者 LRP …

2026/10/5 14:29:57 阅读更多 →
客服系统cheap-first架构:模型分流与低成本FAQ处理实战

客服系统cheap-first架构:模型分流与低成本FAQ处理实战

1. 为什么“cheap-first”不是省钱技巧,而是客服系统架构的底层逻辑 我第一次在客户现场看到那个每分钟烧掉12美元的客服机器人时,手心全是汗。客户用的是某家头部大模型API,单次FAQ问答成本0.8美元,日均3000次查询,月…

2026/10/5 14:29:57 阅读更多 →
政企网站改版选型:从等保测评指标倒推CMS能力清单

政企网站改版选型:从等保测评指标倒推CMS能力清单

一、十月一号之后,改版这件事的性质变了2026 年 8 月 6 日,公安部令第 176 号《公安机关网络空间安全监督检查办法》公布,自 2026 年 10 月 1 日起施行。第一遍看完这份文件时,我的感受是:它对网站改版项目的影响&…

2026/10/5 14:29:57 阅读更多 →
AI Native开发实战:从Anthropic集成到Agent SDLC落地手册

AI Native开发实战:从Anthropic集成到Agent SDLC落地手册

1. 这不是一本“理论手册”,而是一份AI Native团队每天在用的作战日志 “AI Native 团队完整开发落地手册”——看到这个标题,别急着点开PDF或收藏进Notion。它不是那种印在铜版纸上、摆在会议室玻璃柜里供人瞻仰的“方法论白皮书”。我带过三支从0到1搭…

2026/10/5 14:29:57 阅读更多 →
Java+JSP+MySQL电子健康档案系统毕业设计实现与避坑指南

Java+JSP+MySQL电子健康档案系统毕业设计实现与避坑指南

简介:这份资源是面向高校计算机专业学生与Java Web初学者的毕业设计实践包,主题为基于JavaJSPMySQL的电子健康档案系统,可用于课程设计、毕设选题或医疗机构信息化入门参考。压缩包共760个文件,约17.76MB,以js脚本、gi…

2026/10/5 14:28:57 阅读更多 →

日新闻

马斯克杀回智能体战场,Grok 4.5万亿参数撑腰,Cursor接手数字白领项目:用TaoToken统一Key跑通多模型Agent工作流

马斯克杀回智能体战场,Grok 4.5万亿参数撑腰,Cursor接手数字白领项目:用TaoToken统一Key跑通多模型Agent工作流

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 0:00:22 阅读更多 →
AI编程工具插件机制详解:plugin.json配置与加载失败排查指南

AI编程工具插件机制详解:plugin.json配置与加载失败排查指南

1. 从“plugins”这个词说起:它到底在解决什么问题如果你最近在折腾 AI 编程工具,尤其是 Cursor、Codex CLI、Claude Code 这类带 CLI 的编辑器或命令行助手,那你大概率绕不开一个词——plugins。这个词本身不新鲜,从浏览器到 IDE…

2026/10/5 0:00:23 阅读更多 →
第26课:OpenClaw|日志审计与问题诊断:把日志链路改到 TaoToken 的排查清单

第26课:OpenClaw|日志审计与问题诊断:把日志链路改到 TaoToken 的排查清单

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 0:00:23 阅读更多 →

周新闻

KT148A语音芯片外挂8002D功放的工程实践指南

KT148A语音芯片外挂8002D功放的工程实践指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 5:06:42 阅读更多 →
LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

LLC谐振变换器增益公式推导:从FHA等效到完整归一化表达式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 1:10:22 阅读更多 →
ARM架构深度解析:从RISC设计理念到交叉编译实战

ARM架构深度解析:从RISC设计理念到交叉编译实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/5 3:06:17 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 11:40:45 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 9:43:54 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/4 20:14:29 阅读更多 →