什么是 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(第二条 ),以免证书或中级证书轮换时导致全量故障。
防抓包/防中间人的最佳实践清单
-
禁明文:base-config cleartextTrafficPermitted="false",必要域名再局部放开。
-
按域名启用 Pinning:对业务关键域配置 ,并至少两枚 pin(现用+备用) 。
-
发布版不要信任用户 CA:不要在生产配置中出现 ;更不要配 overridePins="true"。
-
调试抓包走 :仅在 debuggable 构建里信任 user,避免把“抓包便利”带到线上。
-
Pin 过期与轮换:合理设置 expiration 并在到期前发版更新 pin;或保留“备用 pin”以无缝换证。
-
验证与自检:
- adb 连代理测试调试版能抓包、发布版抓不到;
- 用 apksigner/openssl 或脚本验证服务端证书 SPKI SHA-256 是否和 pin 对齐;
- 变更证书/中级证书前,先把新公钥指纹加为备用 pin,灰度后再移旧 pin。
-
认知边界:root 设备、内联 hook(Frida/Xposed)、或静态改包仍可能绕过校验;Pinning 只能显著提高成本,而非“绝对不能抓”。(这就是为什么线上禁用用户 CA和代码层二次校验同样重要。)
参考
- 官方:Network security configuration(含 base-config / domain-config / pin-set / debug-overrides 等)
- OWASP MASTG:到期后的 pin 行为、示例配置与要点
- AOSP 测试与资料:overridePins 行为、调试信任用户 CA 的影响
- 额外阅读:逐域名覆盖、明文/信任根实例与实践