Android 在 Android 9(Pie)[android:targetSdkVersion = 28]之後將網絡通信默認配置爲禁止了明文傳輸。所謂明文傳輸就是Http請求,所以如果我們開發版本高於 28 ,打包之後我們 app 中的 Http 請求都無法成功,將會拋出
W/System.err: java.net.UnknownServiceException: CLEARTEXT communication to **** not permitted by network security policy
的錯誤。
關於 Http 請求的限制歷史:
- 當 Android 6.0(Marshmallow)「(API 23)」發佈時,谷歌提出了清單文件中配置:
android:usesCleartextTraffic
作爲防止意外使用明文通信的手段
<!-- 默認允許所有明文通信 -->
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<!-- 信任系統預裝 CA 證書 -->
<certificates src="system" />
<!-- 信任用戶添加的 CA 證書,Charles 和 Fiddler 抓包工具安裝的證書屬於此類 -->
<certificates src="user" />
</trust-anchors>
</base-config>
- Android 7.0 (Nougat) 通過引入Android網絡安全配置 「Network Security Configuration」特性來過渡開發者配置這個屬性。Android 7.0 ~ 8.0 「(API 24) 至 (API 27)」 之間,客戶端仍可以使用 Http 請求。系統默認網絡安全配置如下
<!-- 默認允許所有明文通信 -->
<base-config cleartextTrafficPermitted="true">
<trust-anchors>
<!-- 信任系統預裝 CA 證書 -->
<certificates src="system" />
</trust-anchors>
</base-config>
- Android 9(Pie)「(API 28)」以後系統默認強制禁止明文傳輸
usesCleartextTraffic = true
且默認只信任系統級別證書,也就是我們在手機,設置-> 加密與憑據 ->信任的憑據 -> 系統tab下的所有證書。
<!-- 默認禁止所有明文通信 -->
<base-config cleartextTrafficPermitted="false">
<trust-anchors>
<!-- 信任系統預裝 CA 證書 -->
<certificates src="system" />
</trust-anchors>
</base-config>
網絡安全配置對我們開發者的影響
如果我們採用默認配置,在我們升級 targetSdkVersion >= 24
後,我們就會遇到 Https 請求無法通過抓包工具配置的證書進行抓包的問題。
當我們升級 targetSdkVersion >= 28
就會出現無法所有的 Http 請求都無法響應的問題。
通過上一節網絡配置版本變化的描述過程我們會發現,原因在於,24 以上不再信任用戶證書了所以抓不了包了,28 以上無法進行http請求的原因是,系統默認不讓進行明文傳輸了。
什麼是網絡安全配置?
上面解釋了這麼配置就可以解決我們遇到的無法抓包和無法進行http請求的問題,我們大概可以理解爲這個「網絡安全配置」其實就是駕馭在代碼之外的一個配置文件,程序讀取配置來決定要不要校驗http請求,是不是信任用戶證書。
可以看出 google 雖然做了限制,但是也給了開發者自由。接下來就要憑着開發者的良心辦事情了。
“最佳”實踐
當然爲了響應 Google 爸爸的要求和用戶信息安全考慮,我們應該儘快升級所有的服務器域名爲 Https 請求。但是對於有時候我們還是有一些域名爲 Http 請求無法及時替換,就需要單獨配置了。而且就正式的 APP 包,我們並不希望可以讓其他人抓包,來給我們服務器帶來安全隱患。
允許明文傳輸
- 方法一
允許明文傳輸有兩種配置方法第一個是在項目的主 module 的 AndroidManifest.xml
的 application 節點下配置
<application
...
<!--允許 -->
android:usesCleartextTraffic="true"
...>
...
</application>
但是這個屬性在 Android 7.0 以後會被 android:networkSecurityConfig
屬性覆蓋。
- 方法二
添加在主工程中配置 res/xml/network_security_config.xml 如果沒有可以新建一個文件。該配置會覆蓋系統默認配置。所以我們可在這裏配置我們自己的想要的網絡配置。配置完成後我們需要在 AndroidManifest.xml
的 application 節點下配置
<application
...
<application android:networkSecurityConfig="@xml/network_security_config"
<!--7.0後會被覆蓋-->
<!--android:usesCleartextTraffic="true"-->
...>
...
</application>
- 如何配置
network_security_config
可包含:
0 或 1 個 <base-config>
基本配置,也就是默認配置。 任意數量的 <domain-config>
可以規定任意域名的請求配置 0 或 1 個 <debug-overrides>
debug 模式下域名的配置,可用於調試下進行一些獨立配置。
如果我們需要只需要支持某些域名下的明文傳輸,就可以利用 domain-config 來進行單獨配置
<network-security-config>
<!--允許有多個 domain-confing 該domain-config 下的domain 域名允許明文傳輸-->
<domain-config cleartextTrafficPermitted="true">
<!--includeSubdomains 是否是包含子域名-->
<domain includeSubdomains="true">example.com</domain>
<domain includeSubdomains="true">cdn.example2.com</domain>
</domain-config>
<!--除了domain-config 的標籤下的域名都不允許明文傳輸-->
<base-config cleartextTrafficPermitted="false" />
</network-security-config>
信任用戶證書
比如我們需要允許debug模式下允許抓包,也就是信任 user 證書可以進行下面的配置
<network-security-config>
<!-- 支持 Android 7.0 以上調試時,信任 Charles 等抓包工具的證書 -->
<debug-overrides>
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</debug-overrides>
...
</network-security-config>
在解決網絡完全配置的時候突然想到了 Https 證書驗證的問題,爲什麼我們APP本地沒有安裝證書,使用 OkHttp 也不用忽略證書驗證,同樣訪問大多數網站的時候我們也都沒有下載證書。就可以訪問了。其實是因爲 OkHttp 對於通過CA機構頒發的服務器證書,是默認通過校驗的。一些公司的自簽名證書就不行了。比如 12306。
今年年初我花一個月的時間收錄整理了一套知識體系,如果有想法深入的系統化的去學習的,可以私信我【安卓】,我會把我收錄整理的資料都送給大家,幫助大家更快的進階。