在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

一、前置思考

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, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;');
  }

  // 路径穿越防护:规范化 + 前缀校验
  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:

  1. OWASP Top10:展示十大风险及缓解状态,支持一键 OWASP 扫描统计
  2. 输入注入:展示 SQL/XSS/路径穿越/JSON 四类输入的原始值与净化结果,支持执行注入校验演示拦截
  3. 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 接口 最小暴露 + 来源校验
越权访问 查看他人数据 只做前端隐藏 服务端强制鉴权

六、总结

漏洞防护的核心方法论:

  1. 默认安全:组件默认不导出、WebView 默认收紧、输入默认不可信
  2. 输入校验:所有外部输入先净化后使用,参数化防注入
  3. 配置收敛:高危组件配置安全值,不留宽松后门
  4. 持续扫描:OWASP 自检 + 依赖扫描纳入 CI 门禁

落地建议:

  • 建立安全编码规范:输入校验、组件导出、WebView 配置三张检查表
  • 每次发版跑一次 OWASP 自查
  • 依赖扫描接入 CI,有高危漏洞阻塞发布
  • 服务端永远做最后一道防线:客户端校验只是前置,服务端鉴权兜底

移动端漏洞防护的底层逻辑很简单:把"默认不安全"的组件和配置全部改成"默认安全",把"默认信任"的输入全部改成"默认不信任"。做到这两点,70% 的漏洞就消失了。

Logo

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

更多推荐