Android Network Security Config(防抓包相关)

52 阅读4分钟

什么是 Network Security Config

通过一个 XML 文件声明式定制 App 的网络安全策略(无需改代码):是否允许明文 HTTP、每个域名用哪些信任根(CA)、是否做证书/公钥 Pinning、调试版是否临时信任用户证书等。它按“全局 → 域名级覆盖”的优先级生效。

Manifest 中 android:usesCleartextTraffic 只是全局开关;一旦使用 Network Security Config,以 XML 为准(可逐域名细化)。


能配置什么?每项有什么作用?

1)

< base-config>(全局默认)

  • cleartextTrafficPermitted:是否允许明文 HTTP。默认建议 false(全局禁用),再用域名白名单按需放开。

  • :定义默认信任根集合。可选来源:

    • :只信任系统预装 CA(Android 7.0+ 默认行为)。

    • :信任用户安装的 CA(会让抓包工具更容易中间人拦截,发布版不建议)。

    • :把你随 App 分发的私有 CA 或服务端证书放在 res/raw 并纳入信任。

    • overridePins="true"(可选):忽略 pinning,使该来源的证书即使不匹配 pin 也被接受(仅用于非常特殊场景/调试)。

base-config 提供“全局默认”,后文的 domain-config 可逐域名覆盖它。


2)

< domain-config>(按域名细化)

  • example.com :对该域和其子域生效(可添加多条 domain)。

  • 支持与 base-config 相同的:

    • cleartextTrafficPermitted:对该域放开/收紧 HTTP。
    • :为该域指定单独的 CA 集合(常用来只信任系统 CA + 自家私有 CA,屏蔽用户 CA)。
    • :为该域启用证书/公钥 Pinning(见下一节)。
  • 多个 domain-config 并存时,更具体(子域、路径更精确)的优先。


3)

< pin-set>(证书/公钥 Pinning)

  • 作用:把允许的服务器“公钥哈希” (或证书公钥)固定下来,只有证书链中至少一个公钥的 SHA-256(SPKI) 哈希命中列表才通过,从而阻断“装自定义 CA 做中间人抓包”
  • 写法
<pin-set expiration="YYYY-MM-DD">
    <pin digest="SHA-256">Base64(SPKI hash)</pin>
    <!-- 建议至少两条:现用 + 备用 -->
</pin-set>
    • digest 通常用 SHA-256。

    • 建议至少两枚 pin:一枚当前线上证书(或中级证书)的公钥指纹 + 一枚备用密钥,以便将来换证书不中断服务。

    • expiration 到期后该域不再强制 pinning,会回退到该域的 逻辑(用于平滑换证)。

注意:把 放进信任根,并且设置了 overridePins="true",会直接绕过 pinning**;发布版不要用。


4)

< trust-anchors>(信任根集合)

  • 决定 App 认可哪些 CA/证书。配置位置可在 base-config 或 domain-config。

  • 常见组合:

    • 生产环境:只用 system + 必要的 @raw/your_ca不要加 user。
    • 调试环境:在 里临时信任 user,方便抓包联调。
  • overridePins="true":对该来源的证书跳过 pin 校验(极少用;更适合放在调试覆盖里)。


5)

< debug-overrides>(仅调试构建生效)

  • 只在 debuggable=true 的构建生效,常用来临时信任用户 CA便于调试 HTTPS。
<debug-overrides>
  <trust-anchors>
    <certificates src="user" />
    <certificates src="system" />
  </trust-anchors>
</debug-overrides>
  • 这样发布版仍保持严格策略,调试版可以连代理抓包。

你这段 XML 的逐项解读

<network-security-config>
  <base-config cleartextTrafficPermitted="false" />
  <domain-config>
    <domain includeSubdomains="true">jaco.live</domain>
    <pin-set expiration="2123-01-01">
      <pin digest="SHA-256">=</pin>
    </pin-set>
  </domain-config>
</network-security-config>
  • base-config/cleartextTrafficPermitted=false全局禁用 HTTP 明文,只能走 HTTPS。

  • domain-config:对 jaco.live 及全部子域名生效(includeSubdomains=true),因此 *.jaco.live 都会套用下面的 pin。

  • pin-set:对 jaco.live 域名族启用 公钥 Pinning;只要服务器链上的某个证书公钥的 SHA-256 指纹等于你配置的 Base64 值,就通过握手。

  • expiration=2123-01-01:在此日期之后,不再强制 pinning(届时会退回信任根判断)。日期很远,意味着长期强制。

  • 未写 :默认信任 系统 CA信任用户 CA(Android 7.0+ 默认)。这对防中间人抓包是对的。

建议再加备用 pin(第二条 ),以免证书或中级证书轮换时导致全量故障。


防抓包/防中间人的最佳实践清单

  1. 禁明文:base-config cleartextTrafficPermitted="false",必要域名再局部放开。

  2. 按域名启用 Pinning:对业务关键域配置 ,并至少两枚 pin(现用+备用)

  3. 发布版不要信任用户 CA:不要在生产配置中出现 ;更不要配 overridePins="true"。

  4. 调试抓包走 :仅在 debuggable 构建里信任 user,避免把“抓包便利”带到线上。

  5. Pin 过期与轮换:合理设置 expiration 并在到期前发版更新 pin;或保留“备用 pin”以无缝换证。

  6. 验证与自检

    • adb 连代理测试调试版能抓包、发布版抓不到;
    • 用 apksigner/openssl 或脚本验证服务端证书 SPKI SHA-256 是否和 pin 对齐;
    • 变更证书/中级证书前,先把新公钥指纹加为备用 pin,灰度后再移旧 pin。
  7. 认知边界:root 设备、内联 hook(Frida/Xposed)、或静态改包仍可能绕过校验;Pinning 只能显著提高成本,而非“绝对不能抓”。(这就是为什么线上禁用用户 CA代码层二次校验同样重要。)


参考

  • 官方:Network security configuration(含 base-config / domain-config / pin-set / debug-overrides 等)
  • OWASP MASTG:到期后的 pin 行为、示例配置与要点
  • AOSP 测试与资料:overridePins 行为、调试信任用户 CA 的影响
  • 额外阅读:逐域名覆盖、明文/信任根实例与实践