Android网络安全配置:网络安全策略文件详解、明文流量控制、用户证书信任配置

说实话,网络安全配置这块,很多开发者都容易忽略。我记得刚入行那会儿,总觉得只要用了HTTPS就万事大吉。直到有一次,我负责的金融类App被安全团队打回来说「明文流量未限制」——嗯,从那以后我再也不敢小看这个network_security_config.xml了。

今天咱们就好好聊聊Android的网络安全策略文件。说白了,它就是一张白名单,告诉系统:哪些流量可以明文走,哪些必须加密,哪些证书可以信任。

网络安全策略文件是什么?

Android 7.0(API 24)之后,Google引入了一个重要的安全机制——网络安全策略文件。它的核心作用就三个:

  • 控制明文流量:哪些域名允许HTTP明文传输
  • 管理证书信任:哪些CA证书或自签名证书可以被信任
  • 配置调试环境:开发阶段可以放宽限制,发布时收紧

你想想看,如果没有这个文件,App默认是不信任用户安装的证书的。这意味着什么?意味着你连Charles抓包都抓不了。我见过不少团队,开发时直接关掉所有安全限制,上线前又忘了打开——这其实很危险。

核心要点:网络安全策略文件是Android应用的第一道防线。它决定了你的App「信任什么」「允许什么」「拒绝什么」。

配置文件的位置与基本结构

配置文件放在 res/xml/network_security_config.xml,然后在AndroidManifest.xml中引用:

<application
    android:networkSecurityConfig="@xml/network_security_config"
    ... />

基本结构长这样:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="false">
        <trust-anchors>
            <certificates src="system" />
        </trust-anchors>
    </base-config>

    <domain-config cleartextTrafficPermitted="true">
        <domain includeSubdomains="true">example.com</domain>
        <domain includeSubdomains="true">192.168.1.100</domain>
    </domain-config>

    <debug-overrides>
        <trust-anchors>
            <certificates src="user" />
        </trust-anchors>
    </debug-overrides>
</network-security-config>

我个人习惯把配置分成三层:全局策略域名例外调试覆盖。这样结构清晰,不容易出错。

明文流量控制:该紧的时候紧,该松的时候松

明文流量控制,说白了就是HTTP vs HTTPS的问题。Android 9(API 28)之后,默认禁止所有明文流量。但实际开发中,我们难免会遇到一些特殊情况:

  • 内网测试环境,没有配HTTPS证书
  • 某些第三方SDK,还在用HTTP接口
  • 本地开发时,需要连接本地的HTTP服务

这时候就需要用 <domain-config> 来开白名单。我建议的原则是:全局禁止,局部放行

我的经验:曾经有个项目,第三方支付SDK的预下单接口用的是HTTP。我们一开始全局允许了明文流量,结果安全扫描时被标记为高风险。后来改成只对那个特定域名放行,问题就解决了。

配置示例:

<base-config cleartextTrafficPermitted="false" />

<domain-config cleartextTrafficPermitted="true">
    <domain includeSubdomains="true">10.0.2.2</domain>  <!-- 模拟器访问宿主机 -->
    <domain includeSubdomains="true">dev-api.internal.com</domain>
</domain-config>

用户证书信任配置:抓包与安全的平衡

这里有个常见的坑:为什么我装了Charles证书,还是抓不到包?

原因很简单——Android 7.0之后,App默认只信任系统证书,不信任用户安装的证书。Charles的证书是用户级的,所以默认情况下App不认它。

解决办法有两种:

  1. 调试模式信任用户证书:使用 <debug-overrides>,只在debug版本生效
  2. 将Charles证书安装为系统证书:需要root权限,不推荐

我个人强烈推荐第一种方式:

<debug-overrides>
    <trust-anchors>
        <certificates src="system" />
        <certificates src="user" />
    </trust-anchors>
</debug-overrides>

这样配置后,debug包可以正常抓包,release包则不受影响。我曾经见过有人直接把 user 证书加到全局配置里——嗯,这相当于给攻击者开了后门。

警告:千万不要在release版本的全局配置中信任用户证书!否则用户安装一个恶意CA证书,就能轻松劫持你的HTTPS流量。

证书绑定(Certificate Pinning)

如果你对安全性要求更高,可以考虑证书绑定。它比信任CA证书更严格——直接锁定服务器的公钥或证书。

<domain-config>
    <domain includeSubdomains="true">api.yourbank.com</domain>
    <pin-set expiration="2025-12-31">
        <pin digest="SHA-256">47DEQpj8HBSa+/TImW+5JCeuQeRkm5NMpJWZG3hSuFU=</pin>
        <pin digest="SHA-256">GQr5G7sVfLq3tJ8zXy2w4p6n9m0k3j5h7d8s1a2c4f6=</pin>
    </pin-set>
</domain-config>

这里要注意:一定要配置备用证书。我遇到过最惨的一次,是某团队只绑定了一个证书,结果证书过期后App全线崩溃——所有API请求都失败了。

建议至少绑定两个证书:当前证书 + 备用证书。备用证书可以是另一个CA签发的,也可以是自签名的。

知识体系结构图

下面这张图,是我梳理的网络安全策略文件的核心逻辑:

Android网络安全策略文件 network_security_config.xml 明文流量控制 base-config 全局禁止 domain-config 局部放行 证书信任管理 系统证书 用户证书 证书绑定 调试覆盖配置 debug-overrides 核心原则:全局收紧 + 局部放行 + 调试宽松 + 发布严格 不要信任用户证书 | 不要全局允许明文 | 证书绑定要留备用 Android网络安全策略配置逻辑图

实战中的避坑指南

这些年我踩过的坑不少,挑几个典型的说说:

  • 坑一:debug-overrides不生效——检查一下你的build variant是不是真的用了debug签名。有时候CI打包用的release签名,debug-overrides就不认了。
  • 坑二:证书绑定导致App无法更新——证书过期前一定要发版更新pin-set。我建议把过期时间设得比证书实际过期时间早一个月,留出缓冲期。
  • 坑三:明文流量配置冲突——如果同时配置了 <base-config><domain-config>,domain-config的优先级更高。但要注意,<domain-config> 不能嵌套太深,否则容易混淆。
我的小技巧:在debug模式下,我会在App启动时打印当前生效的网络安全策略。这样一眼就能看出配置是否生效,省得反复排查。

总结一下

网络安全策略文件,说白了就是给App画了个「安全边界」。你画得越清晰,攻击者就越难钻空子。我个人建议:

  • 默认禁止明文流量,只对必要域名放行
  • release版本只信任系统证书,debug版本可以加用户证书
  • 证书绑定是好东西,但一定要留备用证书
  • 定期审查你的network_security_config.xml,别让它成为摆设

嗯,今天就聊到这儿。这些配置看起来简单,但用好了真的能挡住不少攻击。下次咱们可以聊聊更深入的HTTPS通信安全话题。


公众号:蓝海资料掘金营,微信deep3321