ネットワーク セキュリティ構成

ネットワーク セキュリティ構成機能により、アプリのコードを修正しなくても、安全な宣言型構成ファイルで、アプリのネットワーク セキュリティの設定をカスタマイズできます。これらの設定は、特定のドメインおよび特定のアプリに対して構成できます。主な機能は次のとおりです。

  • カスタム トラスト アンカー:アプリのセキュアな接続にどの認証局(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 を信頼する。

デフォルトで、すべてのアプリのセキュアな接続(TLS や HTTPS などのプロトコルを使用)は、システムにプレインストールされた CA を信頼し、Android 6.0(API レベル 23)以下をターゲットにしたアプリは、ユーザーが追加した CA ストアも信頼します。アプリは base-config(アプリ全体のカスタマイズ)または domain-config(ドメイン単位のカスタマイズ)を使用して、独自の接続をカスタマイズすることもできます。

カスタムの CA の設定

自己署名 SSL 証明書を使用するホスト、または信頼できる非パブリック CA(社内の CA など)によって SSL 証明書が発行されているホストに接続するケースで説明します。

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>
</network-security-config>

PEM または DER 形式で、自己署名または非パブリック CA 証明書をres/raw/my_ca に追加します。

信頼できる CA の制限

システムによって信頼されているすべての CA をアプリで信頼したくない場合は、信頼する CA を制限できます。これにより、他の CA が発行した偽造証明書からアプリを保護できます。

信頼できる CA を制限するための設定は、特定のドメインでカスタムの CA を信頼する設定と似ています。ただし、リソースで複数の CA を指定できる点が異なります。

res/xml/network_security_config.xml:

<?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>

PEM または DER 形式で、信頼できる CA を res/raw/trusted_roots に追加します。PEM 形式を使用する場合、そのファイルには PEM データのみを含めるようにして、余分なテキストを含めないでください。1 つだけでなく複数の <certificates> 要素を指定できます。

信頼できる CA の追加

システムで信頼されていない CA を、アプリが追加で信頼しなければならない場合があります。これは、システムに CA がまだ組み込まれていなかったり、CA が Android システムに組み込まれるための要件を満たしていないことが原因です。CA を追加するには、アプリの構成で複数の証明書ソースを指定します。

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 を使用して、android:debuggabletrue の場合にのみ信頼されるデバッグ限定の CA を指定できます。通常、IDE およびビルドツールによって、非リリースビルドには自動的にこのフラグが設定されます。

この方法は、通常の条件付きコードよりも安全です。セキュリティ対策として、アプリストアでは debuggable とマークされたアプリは拒否されるからです。

res/xml/network_security_config.xml:

<?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>

クリアテキスト トラフィックのオプトアウト

アプリで、セキュアな接続のみを使用して接続する場合、それらの接続先に対して(HTTPS ではなく暗号化されていない HTTP プロトコルを使用する)クリアテキストのサポートを除外できます。このオプションにより、バックエンド サーバーなどの外部ソースが提供する URL の変更によって、アプリで思わぬパフォーマンスの低下が発生するのを防ぐことができます。詳細については、NetworkSecurityPolicy.isCleartextTrafficPermitted() をご覧ください。

たとえば、アプリで secure.example.com へのすべての接続には常に HTTPS を使用して、機密性の高いトラフィックを有害なネットワークから保護することが必要な場合があります。

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 が偽造証明書を発行すると、アプリは man-in-the-middle 攻撃のリスクにさらされます。アプリによっては、信頼する CA を制限するか、証明書をピン留めすることで、受け入れる証明書を制限できます。

証明書をピン留めするには、パブリック キーのハッシュによって証明書のセットを指定します(X.509 証明書の SubjectPublicKeyInfo)。証明書チェーンが有効になるのは、証明書チェーンに 1 つ以上のピン留めされたパブリック キーが含まれている場合のみです。

証明書のピン留めを使用するときは、必ずバックアップのキーを含めてください。そうすれば、新しいキーに切り替えたり、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 7.0(API レベル 24)以上を対象とするアプリのデフォルトの構成は次のとおりです。

<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 証明書のソースです。各証明書は次のいずれかです。
  • X.509 証明書を含むファイルを指す未加工のリソース ID。証明書は、DER または PEM 形式でエンコードする必要があります。PEM 証明書の場合、ファイルには PEM 以外の余分なデータ(コメントなど)を含めないでください。
  • "system": プレインストールされたシステムの CA 証明書
  • "user": ユーザーが追加した CA 証明書
overridePins

ソースから取得した CA が証明書のピン留めを回避するかどうかを指定します。"true" の場合、このソースから取得したいずれかの CA を使用して署名された証明書チェーンでピン留めは実行されません。この設定は、CA をデバッグしたり、アプリのセキュアなトラフィックで man-in-the-middle をテストするときに役立ちます。

デフォルトは "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
PIN の生成にはダイジェスト アルゴリズムが使用されます。現在サポートされているのは "SHA-256" のみです。