Android网络安全配置:网络安全策略文件详解、明文流量控制、用户证书信任配置
说实话,网络安全配置这块,很多开发者都容易忽略。我记得刚入行那会儿,总觉得只要用了HTTPS就万事大吉。直到有一次,我负责的金融类App被安全团队打回来说「明文流量未限制」——嗯,从那以后我再也不敢小看这个network_security_config.xml了。
今天咱们就好好聊聊Android的网络安全策略文件。说白了,它就是一张白名单,告诉系统:哪些流量可以明文走,哪些必须加密,哪些证书可以信任。
网络安全策略文件是什么?
Android 7.0(API 24)之后,Google引入了一个重要的安全机制——网络安全策略文件。它的核心作用就三个:
- 控制明文流量:哪些域名允许HTTP明文传输
- 管理证书信任:哪些CA证书或自签名证书可以被信任
- 配置调试环境:开发阶段可以放宽限制,发布时收紧
你想想看,如果没有这个文件,App默认是不信任用户安装的证书的。这意味着什么?意味着你连Charles抓包都抓不了。我见过不少团队,开发时直接关掉所有安全限制,上线前又忘了打开——这其实很危险。
配置文件的位置与基本结构
配置文件放在 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> 来开白名单。我建议的原则是:全局禁止,局部放行。
配置示例:
<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不认它。
解决办法有两种:
- 调试模式信任用户证书:使用
<debug-overrides>,只在debug版本生效 - 将Charles证书安装为系统证书:需要root权限,不推荐
我个人强烈推荐第一种方式:
<debug-overrides>
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</debug-overrides>
这样配置后,debug包可以正常抓包,release包则不受影响。我曾经见过有人直接把 user 证书加到全局配置里——嗯,这相当于给攻击者开了后门。
证书绑定(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签发的,也可以是自签名的。
知识体系结构图
下面这张图,是我梳理的网络安全策略文件的核心逻辑:
实战中的避坑指南
这些年我踩过的坑不少,挑几个典型的说说:
- 坑一:debug-overrides不生效——检查一下你的build variant是不是真的用了debug签名。有时候CI打包用的release签名,debug-overrides就不认了。
- 坑二:证书绑定导致App无法更新——证书过期前一定要发版更新pin-set。我建议把过期时间设得比证书实际过期时间早一个月,留出缓冲期。
- 坑三:明文流量配置冲突——如果同时配置了
<base-config>和<domain-config>,domain-config的优先级更高。但要注意,<domain-config>不能嵌套太深,否则容易混淆。
总结一下
网络安全策略文件,说白了就是给App画了个「安全边界」。你画得越清晰,攻击者就越难钻空子。我个人建议:
- 默认禁止明文流量,只对必要域名放行
- release版本只信任系统证书,debug版本可以加用户证书
- 证书绑定是好东西,但一定要留备用证书
- 定期审查你的network_security_config.xml,别让它成为摆设
嗯,今天就聊到这儿。这些配置看起来简单,但用好了真的能挡住不少攻击。下次咱们可以聊聊更深入的HTTPS通信安全话题。