鸿蒙安全漏洞高级防护:OWASP移动Top10风险排查/输入注入防御/WebView安全/组件劫持防护方案



一、前置思考
1.1 漏洞为何反复出现
大部分移动应用的安全事故,翻来覆去就是那几类漏洞:SQL 注入、XSS、不安全的 WebView 配置、组件导出泄露。OWASP 总结了移动端 Top 10 风险,其中一大半与"输入处理"和"组件配置"有关——不是漏洞多高级,而是开发时根本没设防。
我们统计一下移动端漏洞分布,会得到一个扎心的结论:
| 漏洞类型 | 占比 | 典型原因 |
|---|---|---|
| 不安全配置(调试开关、组件导出) | ~30% | 上线忘收敛 |
| 输入注入(SQL/XSS/命令) | ~25% | 没做输入校验 |
| 不安全的 WebView | ~15% | 默认配置未收紧 |
| 加密/存储问题 | ~15% | 明文存储 |
| 其他 | ~15% | 各类业务逻辑漏洞 |
超过一半的漏洞不是"攻击者多聪明",而是"开发者没设防"。防护思路应该是**“默认安全 + 输入校验 + 配置收敛”**:
- 所有外部输入默认不可信,先校验后使用
- WebView 等高风险组件默认收紧配置
- 组件默认不导出,需要时显式声明
1.2 本文结构
本文从 OWASP Mobile Top 10 概览、输入注入防御、WebView 安全配置、组件劫持防护四个维度展开,最后给出安全编码规范与实战落地。
二、核心原理
2.1 OWASP Mobile Top 10 概览
| 编号 | 风险 | 典型场景 | 缓解 |
|---|---|---|---|
| A01 | 访问控制失效 | 越权访问他人数据 | 服务端强制校验 |
| A02 | 加密失败 | 明文存储/弱算法 | 强算法 + 密钥托管 |
| A03 | 注入攻击 | SQL/命令注入 | 参数化 + 白名单 |
| A04 | 不安全设计 | 缺少威胁建模 | 安全设计评审 |
| A05 | 安全配置错误 | 调试开关上线 | 基线配置检查 |
| A06 | 脆弱组件 | 使用有漏洞的库 | 依赖扫描升级 |
| A07 | 身份认证失效 | 弱口令/无 MFA | 强口令 + 多因素 |
| A08 | 数据完整性失效 | 未做签名校验 | 签名 + 哈希校验 |
| A09 | 日志监控不足 | 无审计日志 | 全量审计 |
| A10 | SSRF | 服务端请求伪造 | URL 白名单 |
解读三个最容易踩的风险:
A01 访问控制失效是移动端越权漏洞的根源。典型场景:应用只做了"前端隐藏",未授权用户可以修改请求参数访问他人数据(IDOR 漏洞)。缓解必须在服务端做权限校验——客户端校验只能防君子,防不了篡改请求的攻击者。
A05 安全配置错误是最"冤"的漏洞:调试开关、测试账号、日志全开,上线时忘了关。缓解方法是"基线配置 + 构建门禁":构建产物自动检查 debug 开关、测试环境地址等敏感配置。
A06 脆弱组件是供应链攻击的入口:使用的第三方库有已知 CVE 漏洞。缓解方法是在 CI 中集成依赖漏洞扫描,高危漏洞阻塞发布。
2.2 输入注入防御
输入校验是防注入的第一道防线:
// 输入校验管道示意
class InputSanitizer {
// SQL 注入防护:参数化查询
static sanitizeSql(input: string): string {
// 单引号转义 + 关键词过滤
return input.replace(/'/g, "''");
}
// XSS 防护:HTML 转义
static sanitizeHtml(input: string): string {
return input
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"');
}
// 路径穿越防护:规范化 + 前缀校验
static sanitizePath(input: string): string {
// 去除 ../ 等相对路径符号
return input.replace(/\.\.\//g, '');
}
}
| 注入类型 | 恶意输入示例 | 防护手段 |
|---|---|---|
| SQL注入 | ' OR 1=1 -- |
参数化查询/转义 |
| XSS | <script>alert(1)</script> |
HTML 转义 |
| 路径穿越 | ../../../etc/passwd |
路径规范化 |
| 命令注入 | ; rm -rf / |
禁用 shell |
输入校验的三个层次:
(1)语法校验
格式校验:邮箱格式、手机号格式、长度限制、字符集白名单。语法校验能拦掉大部分畸形输入。
(2)语义校验
业务校验:金额必须大于 0、状态必须是枚举值、权限必须满足。语义校验拦的是"格式正确但业务非法"的输入。
(3)输出编码
存储后再次输出时按上下文编码:渲染到 HTML 时转义、拼接到 SQL 时参数化、拼接到 URL 时 URL 编码。输出编码是防二次注入(存储型 XSS)的关键。
关键原则:校验 ≠ 过滤。过滤(删掉危险字符)容易绕过(编码变体、双写等),正确做法是"白名单 + 编码"。白名单确定"允许什么",编码保证"输出的数据不会被执行"。
2.3 WebView 安全配置
WebView 是移动应用最高危的组件之一,必须默认收紧:
// WebView 安全配置示意
import { webview } from '@kit.ArkWeb';
function hardenWebview(controller: webview.WebviewController): void {
// 1. 按需开启 JS:仅可信页面开启
// 2. 禁止本地文件访问
// 3. 禁止混合内容(HTTP 资源加载到 HTTPS 页面)
// 4. 拦截白名单外的 URL
controller.setJavaScriptCanAccessOnlyTrustedDomains(true);
}
| 配置项 | 安全值 | 说明 |
|---|---|---|
| JavaScriptEnabled | 按需开启 | 仅可信页面开启 JS |
| allowFileAccess | false | 禁止本地文件访问 |
| mixedContentMode | NEVER_ALLOW | 禁止混合内容 |
| allowFileAccessFromFileURLs | false | 禁止 file:// 互访 |
| allowUniversalAccessFromFileURLs | false | 禁止任意源访问 |
| URL 拦截 | 白名单 | 拦截危险域名 |
WebView 漏洞的典型攻击链:
攻击者控制页面(XSS/钓鱼)
│
├── 开启 JS → 页面可执行任意 JS
├── 开启 file 访问 → JS 可读本地文件
├── 未加 URL 白名单 → 页面可跳转到任意地址
└── 未禁混合内容 → 页面加载 HTTP 资源(可被劫持)
WebView 与 JS 交互的安全要点:
- 用
addJavaScriptInterface暴露原生方法时,只暴露最小必要方法,且方法内校验来源页面 - JS 回调的字符串参数默认不可信,进入原生逻辑前做校验
- 高安全场景用 HTTPS + 内容安全策略(CSP)双重限制
2.4 组件劫持防护
- 组件导出控制:
exported: false为默认,需要跨应用调用才显式导出 - 能力白名单:导出的能力限定调用方(权限校验)
- Intent 校验:收到的 Want 参数必须校验来源与内容
组件劫持的两种攻击:
攻击一:任意拉起(组件被导出且无校验)
恶意应用 → startAbility 拉起受害应用的敏感页面 → 窃取界面数据
攻击二:返回结果劫持(exported + 无返回校验)
恶意应用 → 等待受害应用返回结果 → 截获返回的敏感数据
防护清单:
- 无跨应用需求的能力一律
exported: false - 必须导出的能力:限定调用方(权限校验)、校验来源、最小化返回数据
- 收到的 Want 参数:校验 action、uri、extra 字段,防恶意构造
- 敏感页面(支付、登录)即便导出也加签名校验
三、典型攻击场景还原
3.1 场景一:SQL 注入拖库
攻击者操作:
1. 登录框输入 ' OR 1=1 --
2. 后端拼接 SQL: SELECT * FROM user WHERE name='' OR 1=1 --'
3. 绕过认证,读取全部用户数据
被拦截的环节:
① 参数化查询:输入作为参数绑定,不参与 SQL 拼接
② 输入校验:SQL 注入特征(单引号/OR/--)被拦截
③ 即使注入成功,数据库账号权限最小化,无法越权读取
3.2 场景二:WebView 钓鱼
攻击者操作:
1. 诱导用户点击恶意链接
2. WebView 加载钓鱼页面,JS 全开 + 可读本地文件
3. 窃取用户输入/本地数据
被拦截的环节:
① URL 白名单:非白名单域名被拦截
② 仅可信页面开启 JS,钓鱼页面 JS 禁用
③ 禁止 file 访问,JS 读不到本地文件
④ 混合内容禁止,页面无法加载被劫持的 HTTP 资源
3.3 场景三:组件任意拉起
攻击者操作:
1. 恶意应用调 startAbility 拉起银行 App 的转账页面
2. 诱导用户完成转账
被拦截的环节:
① 转账页面 exported: false → 无法被外部拉起
② 必须导出的页面做了调用方权限校验
③ 拉起时校验 Want 参数来源与内容,异常拒绝
四、实战落地
对应 Demo 页面:entry/src/main/ets/pages/VulnerabilityProtectionDemo.ets
Demo 包含三个 Tab:
- OWASP Top10:展示十大风险及缓解状态,支持一键 OWASP 扫描统计
- 输入注入:展示 SQL/XSS/路径穿越/JSON 四类输入的原始值与净化结果,支持执行注入校验演示拦截
- WebView安全:展示 6 项 WebView 安全配置及安全值,支持一键应用加固
// Demo 核心:输入注入校验
private runInputChecks(): void {
let blocked: number = 0;
for (let i: number = 0; i < this.inputTests.length; i++) {
if (this.inputTests[i].blocked) {
blocked++;
}
}
this.inputSummary = '输入注入校验完成:' + blocked.toString() +
' 条恶意输入已被拦截/净化,0 条流入业务逻辑';
}
4.1 安全编码规范落地
把防护变成团队习惯,靠的是编码规范 + 检查表 + CI 门禁三件套:
三张检查表:
| 检查表 | 检查项 |
|---|---|
| 输入校验表 | 所有外部输入是否经过校验管道?校验是白名单吗?输出是否编码? |
| 组件导出表 | 每个组件 exported 状态?导出的是否有权限校验?Want 参数是否校验? |
| WebView 配置表 | JS 是否按需开启?file 访问是否关闭?混合内容是否禁止?URL 白名单是否配置? |
CI 门禁:
- 依赖漏洞扫描:
ohpm audit等工具检查 CVE,高危阻塞发布 - 静态代码扫描:检测拼接 SQL、明文日志、导出组件等模式
- 构建基线检查:debug 开关、测试地址、签名信息核查
4.2 发版前安全自查清单
- OWASP Top 10 逐项自查完成
- 所有外部输入经过校验管道
- 所有组件 exported 状态复核
- WebView 配置按安全基线收敛
- 依赖扫描无高危漏洞
- 调试开关/测试地址已移除
- 全流量 HTTPS + 证书校验
五、避坑速查
| 坑 | 现象 | 原因 | 解决 |
|---|---|---|---|
| 组件忘了设 exported | 应用被任意拉起 | 默认导出 | 无跨应用需求一律 exported:false |
| WebView 加载不受信页面 | XSS 执行 | JS 全开 | 按需开 JS + URL 白名单 |
| 拼接 SQL | 注入成功 | 字符串拼接查询 | 全量参数化查询 |
| 调试开关上线 | 泄露内部信息 | 上线未关 debug | 构建产物强制收敛 |
| 依赖漏洞 | 被 CVE 攻击 | 未做依赖扫描 | CI 接入漏洞扫描 |
| 明文传输敏感数据 | 中间人窃取 | 未上 HTTPS | 全流量 HTTPS |
| 校验被绕过 | 过滤可被编码绕过 | 用黑名单过滤 | 白名单 + 输出编码 |
| JS 桥接泄露 | 原生能力被滥用 | 暴露过多 JS 接口 | 最小暴露 + 来源校验 |
| 越权访问 | 查看他人数据 | 只做前端隐藏 | 服务端强制鉴权 |
六、总结
漏洞防护的核心方法论:
- 默认安全:组件默认不导出、WebView 默认收紧、输入默认不可信
- 输入校验:所有外部输入先净化后使用,参数化防注入
- 配置收敛:高危组件配置安全值,不留宽松后门
- 持续扫描:OWASP 自检 + 依赖扫描纳入 CI 门禁
落地建议:
- 建立安全编码规范:输入校验、组件导出、WebView 配置三张检查表
- 每次发版跑一次 OWASP 自查
- 依赖扫描接入 CI,有高危漏洞阻塞发布
- 服务端永远做最后一道防线:客户端校验只是前置,服务端鉴权兜底
移动端漏洞防护的底层逻辑很简单:把"默认不安全"的组件和配置全部改成"默认安全",把"默认信任"的输入全部改成"默认不信任"。做到这两点,70% 的漏洞就消失了。
更多推荐




所有评论(0)