網路安全性設定

「網路安全性設定」功能可讓您在安全的宣告式設定檔中,自訂應用程式的網路安全性設定,且不必修改應用程式程式碼。您可以為特定網域和應用程式調整這些設定。這項功能的主要特性如下:

  • 自訂信任錨點:為應用程式安全連線自訂信任的憑證授權單位 (CA)。例如,信任特定的自行簽署憑證,或限制應用程式信任的公開 CA 組合。
  • 僅限偵錯的覆寫機制:安全地偵錯應用程式中的安全連線,不會對已安裝應用程式的使用者增添風險。
  • 選擇不採用明文流量:避免應用程式意外使用明文 (未加密) 的流量。
  • 憑證綁定:限制應用程式的安全連線只能使用特定憑證。

新增網路安全性設定檔案

「網路安全性設定」功能會使用 XML 檔案,您可以在該檔案中指定應用程式設定。您必須在應用程式資訊清單中,加入一個指向該檔案的項目。下列資訊清單節錄內容示範了建立此項目的方法:

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
    <application android:networkSecurityConfig="@xml/network_security_config"
                    ... >
        ...
    </application>
</manifest>

自訂信任的 CA

您可能會希望應用程式信任自訂的 CA 組合,而非平台預設值。這種情況最常見的原因包括:

  • 連線至含有自訂 CA 的主機,例如自行簽署或在公司內部核發的 CA。
  • 將 CA 限制在您信任的 CA 組合,而非所有預先安裝的 CA。
  • 信任系統中未包含的其他 CA。

根據預設,所有應用程式的安全連線 (使用傳輸層安全標準 (TLS) 和 HTTPS 等通訊協定) 會信任預先安裝的系統 CA,指定 Android 6.0 (API 級別 23) 以下版本的應用程式也會信任使用者新增的 CA 儲存庫。您可以使用 base-config (針對應用程式範圍自訂) 或 domain-config (針對個別網域自訂),自訂應用程式的連線。

設定自訂 CA

建議您在連線至主機時,該主機使用自行簽署的 SSL 憑證,或是由您信任的非公開 CA (例如貴公司的內部 CA) 核發的 SSL 憑證。以下程式碼片段示範如何在 res/xml/network_security_config.xml 中為自訂 CA 設定應用程式:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config>
        <domain includeSubdomains="true">example.com</domain>
        <trust-anchors>
            <certificates src="@raw/my_ca"/>
        </trust-anchors>
    </domain-config>
</network-security-config>

請將自行簽署或非公開的 CA 憑證,以 PEM 或 DER 格式新增至 res/raw/my_ca

限制信任的 CA 組合

如果您不希望應用程式信任符合系統信任的所有 CA,可以改為指定一組數量較少的信任 CA。這麼做可防止應用程式信任其他 CA 核發的詐欺憑證。

這項設定會限制信任 CA 的組合,因此與針對特定網域信任自訂 CA 類似,不同之處在於前者的多個 CA 是在資源中提供。下列程式碼片段示範如何在 res/xml/network_security_config.xml 中,限制應用程式的信任 CA 組合:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config>
        <domain includeSubdomains="true">secure.example.com</domain>
        <domain includeSubdomains="true">cdn.example.com</domain>
        <trust-anchors>
            <certificates src="@raw/trusted_roots"/>
        </trust-anchors>
    </domain-config>
</network-security-config>

將信任的 CA 以 PEM 或 DER 格式新增至 res/raw/trusted_roots。請注意,如果採用 PEM 格式,則檔案「只能」包含 PEM 資料,且不得含有其他文字。您也可以提供多個 <certificates> 元素,而非單一元素。

信任其他 CA

您可能會希望應用程式信任系統不信任的其他 CA,例如系統尚未納入的 CA,或是 CA 不符合納入 Android 系統的條件。您可以在 res/xml/network_security_config.xml 中使用程式碼,為設定指定多個憑證來源,如以下節錄內容所示。

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

設定用於偵錯的 CA

對透過 HTTPS 連線的應用程式偵錯時,建議您連線至沒有為實際執行伺服器提˙供 SSL 憑證的本機開發伺服器。如想支援這項功能而不修改應用程式的程式碼,您可以使用 debug-overrides 指定僅供偵錯的 CA,「只」android:debuggabletrue 時,才信任該 CA。通常,IDE 和建構工具會為非發布子版本自動設定這個標記。

這比一般的條件式程式碼更為安全,因為基於安全考量,應用程式商店不接受標示為可進行偵錯的應用程式。

以下節錄說明如何在 res/xml/network_security_config.xml 中指定僅供偵錯的 CA:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <debug-overrides>
        <trust-anchors>
            <certificates src="@raw/debug_cas"/>
        </trust-anchors>
    </debug-overrides>
</network-security-config>

選擇停用明文流量

注意:本節指南僅適用於指定 Android 8.1 (API 級別 27) 以下版本的應用程式。自 Android 9 (API 級別 28) 開始,系統會預設停用明文支援功能。

如果您希望應用程式只使用安全連線連結至目的地,可以選擇對這些目的地停用明文 (使用未加密的 HTTP 通訊協定,而非 HTTPS) 支援功能。這個選項可防止因為外部來源 (如後端伺服器) 提供的網址有變,導致應用程式發生迴歸錯誤。詳情請參閱 NetworkSecurityPolicy.isCleartextTrafficPermitted()

例如,您可能希望確保應用程式一律透過 HTTPS 連線至 secure.example.com,以保護來自惡意網路的敏感流量。

以下節錄說明如何在 res/xml/network_security_config.xml 中停用明文:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="false">
        <domain includeSubdomains="true">secure.example.com</domain>
    </domain-config>
</network-security-config>

綁定憑證

一般來說,應用程式會信任所有預先安裝的 CA。如果這類 CA 發送詐欺憑證,應用程式會有遭受路徑上攻擊的風險。有些應用程式為了限制接受的憑證組合,會限制要信任的 CA 組合,或是綁定憑證。

系統會使用公開金鑰 (X.509 憑證的 SubjectPublicKeyInfo) 雜湊值,提供一組憑證來綁定憑證。只有憑證鏈結含有至少一個綁定的公開金鑰時,該鏈結才有效。

請注意,使用憑證綁定功能時,建議您一律加入備用金鑰,這樣一來,若系統強制要求您改用新金鑰或變更 CA (綁定至 CA 憑證或該 CA 的中繼憑證時),應用程式的連線能力就不會受到影響。否則,您必須向應用程式推送更新才能恢復連線。

此外,您也可以為綁定憑證設定到期時間,期限過後就不再綁定憑證。這有助於防止尚未更新的應用程式發生連線問題。不過,如果為綁定憑證設定到期時間,攻擊者就有可能略過已綁定的憑證。

以下節錄說明如何在 res/xml/network_security_config.xml 中綁定憑證:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config>
        <domain includeSubdomains="true">example.com</domain>
        <pin-set expiration="2018-01-01">
            <pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin>
            <!-- backup pin -->
            <pin digest="SHA-256">fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=</pin>
        </pin-set>
    </domain-config>
</network-security-config>

設定繼承行為

系統會繼承未在特定設定中指定的值。這項行為可允許更複雜的設定,同時保持設定檔易於讀取。

例如,未在 domain-config 中設定的值會從父項 domain-config (如果是巢狀結構) 擷取;如果不是巢狀結構,則從 base-config 擷取。未在 base-config 中設定的值會使用平台預設值。

舉例來說,假設所有連至 example.com 的子網域連線都必須使用自訂 CA 組合。此外,系統允許傳送至這些網域的明文流量,但連線至 secure.example.com「除外」。如果在 example.com 的設定中為 secure.example.com 的設定建立巢狀結構,就不必複製 trust-anchors

以下節錄顯示此巢狀結構在 res/xml/network_security_config.xml 中呈現的內容:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config>
        <domain includeSubdomains="true">example.com</domain>
        <trust-anchors>
            <certificates src="@raw/my_ca"/>
        </trust-anchors>
        <domain-config cleartextTrafficPermitted="false">
            <domain includeSubdomains="true">secure.example.com</domain>
        </domain-config>
    </domain-config>
</network-security-config>

設定檔格式

「網路安全性設定」功能採用 XML 檔案格式。檔案的整體結構如以下程式碼範例所示:

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

    <domain-config>
        <domain>android.com</domain>
        ...
        <trust-anchors>
            <certificates src="..."/>
            ...
        </trust-anchors>
        <pin-set>
            <pin digest="...">...</pin>
            ...
        </pin-set>
    </domain-config>
    ...
    <debug-overrides>
        <trust-anchors>
            <certificates src="..."/>
            ...
        </trust-anchors>
    </debug-overrides>
</network-security-config>

以下各節說明檔案格式的語法和其他詳細資料。

<network-security-config>

可包含:
0 或 1 個 <base-config>
任意數量的 <domain-config>
0 或 1 個 <debug-overrides>

<base-config>

語法:
<base-config cleartextTrafficPermitted=["true" | "false"]>
    ...
</base-config>
可包含:
<trust-anchors>
說明:
如果連線的目的地不在 domain-config 涵蓋範圍內,則連線會採用預設設定。

未設定的值都會採用平台預設值。

若應用程式指定 Android 9 (API 級別 28) 以上版本,其預設設定如下:

<base-config cleartextTrafficPermitted="false">
    <trust-anchors>
        <certificates src="system" />
    </trust-anchors>
</base-config>

若應用程式指定 Android 7.0 (API 級別 24) 至 Android 8.1 (API 級別 27) 版本,其預設設定如下:

<base-config cleartextTrafficPermitted="true">
    <trust-anchors>
        <certificates src="system" />
    </trust-anchors>
</base-config>

若應用程式指定 Android 6.0 (API 級別 23) 以下版本,其預設設定如下:

<base-config cleartextTrafficPermitted="true">
    <trust-anchors>
        <certificates src="system" />
        <certificates src="user" />
    </trust-anchors>
</base-config>

<domain-config>

語法:
<domain-config cleartextTrafficPermitted=["true" | "false"]>
    ...
</domain-config>
可包含:
1 或多個 <domain>
0 或 1 個 <trust-anchors>
0 或 1 個 <pin-set>
任意數量的巢狀 <domain-config>
說明:
根據 domain 元素的定義,用於連線至特定目的地的設定。

請注意,如果多個 domain-config 元素涵蓋某個目的地,則會使用相符網域規則最明確 (最長) 的設定。

<domain>

語法:
<domain includeSubdomains=["true" | "false"]>example.com</domain>
屬性:
includeSubdomains
如果設為 "true",這項網域規則須與網域和所有子網域 (包括子網域的子網域) 相符。否則,只有完全相符的網域會套用此規則。

<debug-overrides>

語法:
<debug-overrides>
    ...
</debug-overrides>
可包含:
0 或 1 個 <trust-anchors>
說明:
android:debuggable"true" 時要套用的覆寫設定,IDE 和建構工具產生的非發布子版本通常屬於這種情況。在 debug-overrides 中指定的信任錨點會新增至所有其他設定,當伺服器的憑證鏈結使用其中一個僅供偵錯的信任錨點時,系統不會執行憑證綁定作業。如果 android:debuggable"false",則系統會完全忽略此部分。

<trust-anchors>

語法:
<trust-anchors>
...
</trust-anchors>
可包含:
任意數量的 <certificates>
說明:
安全連線的信任錨點集合。

<certificates>

語法:
<certificates src=["system" | "user" | "raw resource"]
              overridePins=["true" | "false"] />
說明:
trust-anchors 元素的 X.509 憑證集合。
屬性:
src
CA 憑證的來源。可以是下列其中一種:
  • 原始資源 ID,指向包含 X.509 憑證的檔案。憑證必須以 DER 或 PEM 格式編碼。如果是 PEM 憑證,則檔案「不得」包含其他非 PEM 格式的資料。
  • "system",此為預先安裝系統的 CA 憑證來源
  • "user",此為使用者新增的 CA 憑證來源
overridePins

指出此來源的 CA 是否要略過憑證綁定功能。如果設為 "true",則系統不會在由此來源的其中一個 CA 簽署的憑證鏈結上,執行綁定作業。不管是要偵錯 CA,或是測試應用程式安全流量是否遭到中間人攻擊,這項做法都很實用。

預設值為 "false",但如果是在 debug-overrides 元素中指定,則預設值為 "true"

<pin-set>

語法:
<pin-set expiration="date">
...
</pin-set>
可包含:
任意數量的 <pin>
說明:
一組公開金鑰綁定憑證。如要讓系統信任安全連線,該信任鏈結中的其中一個公開金鑰必須位於綁定憑證組合中。請參閱 <pin>,瞭解綁定憑證的格式。
屬性:
expiration
綁定憑證的到期日,格式為 yyyy-MM-dd,在該日期過後憑證將失效,系統也會停止綁定該憑證。如未設定這項屬性,綁定憑證就不會過期。

設定到期日可防止應用程式因未收到綁定憑證的更新內容 (例如使用者停止更新應用程式),導致發生連線問題。

<pin>

語法:
<pin digest=["SHA-256"]>base64 encoded digest of X.509
    SubjectPublicKeyInfo (SPKI)</pin>
屬性:
digest
用於產生綁定憑證的摘要演算法。目前僅支援 "SHA-256"

其他資源

如要進一步瞭解網路安全性設定,請參閱以下資源。

程式碼研究室