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

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

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

PEM または DER 形式の自己署名証明書または非パブリック CA 証明書を 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>

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

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

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

以下の抜粋では、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)以上では、クリアテキストのサポートがデフォルトで無効になっています。

アプリがセキュアな接続のみを使用して接続先に接続する場合は、その接続先へのクリアテキストのサポート(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 が不正な証明書を発行すると、アプリはオンパス攻撃のリスクにさらされます。一部のアプリでは、信頼する 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 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 証明書のソースです。各証明書は次のいずれかです。
  • X.509 証明書を含むファイルを指す未加工リソース ID。証明書は 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" のみです。

参考情報

ネットワーク セキュリティ構成について詳しくは、以下のリソースをご覧ください。

Codelab